From 7e89b7e3f4d4fd6a706e6878c0b9132c1b32e96f Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Fri, 19 Apr 2019 14:48:22 +0100 Subject: [PATCH 01/33] add concurrent load tests --- .../ProviderAgnostic/ReaderTest/ReaderTest.cs | 370 ++++++++++++++++++ 1 file changed, 370 insertions(+) diff --git a/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs b/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs index d0913494a306..e4f20179617a 100644 --- a/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs +++ b/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.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. +using System.Collections.Generic; using System.Data.Common; using System.IO; +using System.Linq; using System.Text; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace System.Data.SqlClient.ManualTesting.Tests @@ -266,5 +270,371 @@ public static void TestMain() } } } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public static async Task TestConcurrentLoadSync() + { + ConcurrentLoadContext context = new ConcurrentLoadContext( + providerFactory: SqlClientFactory.Instance, + connectionString: DataTestUtility.TcpConnStr, + mode: ConcurrentLoadContext.Mode.Async, + warmupSeconds: 1, + executionSeconds: 60, + threadCount: Environment.ProcessorCount * 4 + ); + var (transactionPerSecond, average, stdDeviation) = await context.Run(); + Assert.InRange(transactionPerSecond, 1, int.MaxValue); + Assert.True(average > 0); + Assert.True(stdDeviation != 0); + } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public static async Task TestConcurrentLoadAsync() + { + ConcurrentLoadContext context = new ConcurrentLoadContext( + providerFactory: SqlClientFactory.Instance, + connectionString: DataTestUtility.TcpConnStr, + mode: ConcurrentLoadContext.Mode.Async, + warmupSeconds: 1, + executionSeconds: 60, + threadCount: Environment.ProcessorCount * 4 + ); + var (transactionPerSecond, average, stdDeviation) = await context.Run(); + Assert.InRange(transactionPerSecond, 1, int.MaxValue); + Assert.True(average > 0); + Assert.True(stdDeviation != 0); + } + + public class ConcurrentLoadContext + { + public enum Mode + { + Sync, + Async, + } + + public sealed class Category + { + public int Id; + public string Description; + } + + private readonly DbProviderFactory _providerFactory; + private readonly string _connectionString; + private readonly string _query; + private readonly int _warmupSeconds; + private readonly int _executionSeconds; + private readonly Mode _mode; + + private Func _start; + private Func _stop; + private Func _work; + + private int _counter; + private int _totalTransactions; + private int _threadCount; + private int _running; + private List _results; + private DateTime _startTime; + private DateTime _stopTime; + + public ConcurrentLoadContext(DbProviderFactory providerFactory, string connectionString, Mode mode, int warmupSeconds, int executionSeconds, int threadCount) + { + _providerFactory = providerFactory; + _connectionString = connectionString; + _threadCount = threadCount; + _warmupSeconds = warmupSeconds; + _executionSeconds = executionSeconds; + _query = "SELECT CategoryID,Description FROM Categories"; + _results = new List(_executionSeconds); + _mode = mode; + _start = Start; + _stop = Stop; + switch (_mode) + { + case Mode.Sync: + _work = DoWorkSync; + break; + case Mode.Async: + _work = DoWorkSync; + break; + default: + throw new ArgumentOutOfRangeException(nameof(mode)); + } + } + + public void IncrementCounter() => Interlocked.Increment(ref _counter); + + public bool IsRunning + { + get => _running == 1; + set => Interlocked.Exchange(ref _running, value ? 1 : 0); + } + + public Task DoWorkSync() + { + while (IsRunning) + { + var results = new List(); + + using (var connection = _providerFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + connection.Open(); + + using (var command = connection.CreateCommand()) + { + command.CommandText = _query; + command.Prepare(); + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + results.Add( + new Category + { + Id = reader.GetInt32(0), + Description = reader.GetString(1) + }); + } + } + } + } + + CheckResults(results); + + IncrementCounter(); + } + + return Task.CompletedTask; + } + + public Task DoWorkSyncCaching() + { + using (var connection = _providerFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + connection.Open(); + + using (var command = connection.CreateCommand()) + { + command.CommandText = _query; + command.Prepare(); + + while (IsRunning) + { + var results = new List(); + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + results.Add( + new Category + { + Id = reader.GetInt32(0), + Description = reader.GetString(1) + }); + } + } + + CheckResults(results); + + IncrementCounter(); + } + } + } + + return Task.CompletedTask; + } + + public async Task DoWorkAsync() + { + while (IsRunning) + { + var results = new List(); + + using (var connection = _providerFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + + await connection.OpenAsync(); + + using (var command = connection.CreateCommand()) + { + command.CommandText = _query; + command.Prepare(); + + using (var reader = await command.ExecuteReaderAsync()) + { + while (await reader.ReadAsync()) + { + results.Add( + new Category + { + Id = reader.GetInt32(0), + Description = reader.GetString(1) + }); + } + } + } + } + + CheckResults(results); + + IncrementCounter(); + } + } + + public async Task DoWorkAsyncCaching() + { + using (var connection = _providerFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + + await connection.OpenAsync(); + + using (var command = connection.CreateCommand()) + { + command.CommandText = _query; + command.Prepare(); + + while (IsRunning) + { + var results = new List(); + + using (var reader = await command.ExecuteReaderAsync()) + { + while (await reader.ReadAsync()) + { + results.Add( + new Category + { + Id = reader.GetInt32(0), + Description = reader.GetString(1) + }); + } + } + + CheckResults(results); + + IncrementCounter(); + } + } + } + } + + public async Task<(int transactionPerSecond,double average, double stdDeviation)> Run() + { + IsRunning = true; + + await Task.WhenAll(CreateTasks()); + + _results.Sort(); + _results.RemoveAt(0); + _results.RemoveAt(_results.Count - 1); + + (double avg, double stdDev) = CalculateStdDev(_results); + + int totalTps = (int)(_totalTransactions / (_stopTime - _startTime).TotalSeconds); + + return (totalTps, avg, stdDev); + } + + private async Task Start() + { + await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds)); + + Interlocked.Exchange(ref _counter, 0); + + _startTime = DateTime.UtcNow; + var lastDisplay = _startTime; + + while (IsRunning) + { + await Task.Delay(200); + + DateTime now = DateTime.UtcNow; + int tps = (int)(_counter / (now - lastDisplay).TotalSeconds); + + _results.Add(tps); + + lastDisplay = now; + _totalTransactions += Interlocked.Exchange(ref _counter, 0); + } + } + + private async Task Stop() + { + await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds + _executionSeconds)); + Interlocked.Exchange(ref _running, 0); + _stopTime = DateTime.UtcNow; + } + + private IEnumerable CreateTasks() + { + //yield return Task.Run( + // async () => + // { + + // await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds)); + + // Interlocked.Exchange(ref _counter, 0); + + // _startTime = DateTime.UtcNow; + // var lastDisplay = _startTime; + + // while (IsRunning) + // { + // await Task.Delay(200); + + // var now = DateTime.UtcNow; + // var tps = (int)(_counter / (now - lastDisplay).TotalSeconds); + // var remaining = (int)(_executionSeconds - (now - _startTime).TotalSeconds); + + // _results.Add(tps); + + // lastDisplay = now; + // _totalTransactions += Interlocked.Exchange(ref _counter, 0); + // } + // } + // ); + + yield return Task.Run(_start); + + //yield return Task.Run( + // async () => + // { + // await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds + _executionSeconds)); + + // Interlocked.Exchange(ref _running, 0); + + // _stopTime = DateTime.UtcNow; + // }); + + yield return Task.Run(_stop); + + foreach (var task in Enumerable.Range(0, _threadCount) + .Select(_ => Task.Factory.StartNew(_work, TaskCreationOptions.LongRunning).Unwrap())) + { + yield return task; + } + } + + private static void CheckResults(ICollection results) + { + Assert.NotNull(results); + Assert.Equal(8, results.Count); + } + + private static (double, double) CalculateStdDev(ICollection values) + { + double avg = values.Average(); + double sum = values.Sum(d => Math.Pow(d - avg, 2)); + + return (avg, Math.Sqrt(sum / values.Count)); + } + } } } From 23a78c29abb05724c69fb81603542aeefb617f78 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Fri, 19 Apr 2019 22:52:40 +0100 Subject: [PATCH 02/33] remove commented code and address feedback --- .../ReaderTest/ConcurrentLoadContext.cs | 308 ++++++++++++++++ .../ProviderAgnostic/ReaderTest/ReaderTest.cs | 337 +----------------- ....Data.SqlClient.ManualTesting.Tests.csproj | 1 + 3 files changed, 310 insertions(+), 336 deletions(-) create mode 100644 src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ConcurrentLoadContext.cs diff --git a/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ConcurrentLoadContext.cs b/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ConcurrentLoadContext.cs new file mode 100644 index 000000000000..37fa87f7ea18 --- /dev/null +++ b/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ConcurrentLoadContext.cs @@ -0,0 +1,308 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Data.Common; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace System.Data.SqlClient.ManualTesting.Tests +{ + public class ConcurrentLoadContext + { + public enum Mode + { + Sync, + Async, + } + + public sealed class Category + { + public int Id; + public string Description; + } + + private readonly DbProviderFactory _providerFactory; + private readonly string _connectionString; + private readonly string _query; + private readonly int _warmupSeconds; + private readonly int _executionSeconds; + private readonly Mode _mode; + + private Func _start; + private Func _stop; + private Func _work; + + private int _counter; + private int _totalTransactions; + private int _threadCount; + private int _running; + private List _results; + private DateTime _startTime; + private DateTime _stopTime; + + public ConcurrentLoadContext(DbProviderFactory providerFactory, string connectionString, Mode mode, int warmupSeconds, int executionSeconds, int threadCount) + { + _providerFactory = providerFactory; + _connectionString = connectionString; + _threadCount = threadCount; + _warmupSeconds = warmupSeconds; + _executionSeconds = executionSeconds; + _query = "SELECT CategoryID, Description FROM Categories"; + _results = new List(_executionSeconds); + _mode = mode; + _start = Start; + _stop = Stop; + switch (_mode) + { + case Mode.Sync: + _work = DoWorkSync; + break; + case Mode.Async: + _work = DoWorkAsync; + break; + default: + throw new ArgumentOutOfRangeException(nameof(mode)); + } + } + + public void IncrementCounter() => Interlocked.Increment(ref _counter); + + public bool IsRunning + { + get => _running == 1; + set => Interlocked.Exchange(ref _running, value ? 1 : 0); + } + + public Task DoWorkSync() + { + while (IsRunning) + { + var results = new List(); + + using (var connection = _providerFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + connection.Open(); + + using (var command = connection.CreateCommand()) + { + command.CommandText = _query; + command.Prepare(); + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + results.Add( + new Category + { + Id = reader.GetInt32(0), + Description = reader.GetString(1) + }); + } + } + } + } + + CheckResults(results); + + IncrementCounter(); + } + + return Task.CompletedTask; + } + + public Task DoWorkSyncCaching() + { + using (var connection = _providerFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + connection.Open(); + + using (var command = connection.CreateCommand()) + { + command.CommandText = _query; + command.Prepare(); + + while (IsRunning) + { + var results = new List(); + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + results.Add( + new Category + { + Id = reader.GetInt32(0), + Description = reader.GetString(1) + }); + } + } + + CheckResults(results); + + IncrementCounter(); + } + } + } + + return Task.CompletedTask; + } + + public async Task DoWorkAsync() + { + while (IsRunning) + { + var results = new List(); + + using (var connection = _providerFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + + await connection.OpenAsync(); + + using (var command = connection.CreateCommand()) + { + command.CommandText = _query; + command.Prepare(); + + using (var reader = await command.ExecuteReaderAsync()) + { + while (await reader.ReadAsync()) + { + results.Add( + new Category + { + Id = reader.GetInt32(0), + Description = reader.GetString(1) + }); + } + } + } + } + + CheckResults(results); + + IncrementCounter(); + } + } + + public async Task DoWorkAsyncCaching() + { + using (var connection = _providerFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + + await connection.OpenAsync(); + + using (var command = connection.CreateCommand()) + { + command.CommandText = _query; + command.Prepare(); + + while (IsRunning) + { + var results = new List(); + + using (var reader = await command.ExecuteReaderAsync()) + { + while (await reader.ReadAsync()) + { + results.Add( + new Category + { + Id = reader.GetInt32(0), + Description = reader.GetString(1) + }); + } + } + + CheckResults(results); + + IncrementCounter(); + } + } + } + } + + public async Task<(int transactionPerSecond, double average, double stdDeviation)> Run() + { + IsRunning = true; + + await Task.WhenAll(CreateTasks()); + + _results.Sort(); + _results.RemoveAt(0); + _results.RemoveAt(_results.Count - 1); + + (double avg, double stdDev) = CalculateStdDev(_results); + + int totalTps = (int)(_totalTransactions / (_stopTime - _startTime).TotalSeconds); + + return (totalTps, avg, stdDev); + } + + private async Task Start() + { + await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds)); + + Interlocked.Exchange(ref _counter, 0); + + _startTime = DateTime.UtcNow; + var lastDisplay = _startTime; + + while (IsRunning) + { + await Task.Delay(200); + + DateTime now = DateTime.UtcNow; + int tps = (int)(_counter / (now - lastDisplay).TotalSeconds); + + _results.Add(tps); + + lastDisplay = now; + _totalTransactions += Interlocked.Exchange(ref _counter, 0); + } + } + + private async Task Stop() + { + await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds + _executionSeconds)); + Interlocked.Exchange(ref _running, 0); + _stopTime = DateTime.UtcNow; + } + + private IEnumerable CreateTasks() + { + yield return Task.Run(_start); + + yield return Task.Run(_stop); + + foreach (var task in Enumerable.Range(0, _threadCount) + .Select(_ => Task.Factory.StartNew(_work, TaskCreationOptions.LongRunning).Unwrap())) + { + yield return task; + } + } + + private static void CheckResults(ICollection results) + { + Assert.NotNull(results); + Assert.Equal(8, results.Count); + } + + private static (double, double) CalculateStdDev(ICollection values) + { + double avg = values.Average(); + double sum = values.Sum(d => Math.Pow(d - avg, 2)); + + return (avg, Math.Sqrt(sum / values.Count)); + } + } +} diff --git a/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs b/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs index e4f20179617a..e21df22e91d6 100644 --- a/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs +++ b/src/System.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs @@ -2,12 +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.Data.Common; using System.IO; -using System.Linq; using System.Text; -using System.Threading; using System.Threading.Tasks; using Xunit; @@ -277,7 +274,7 @@ public static async Task TestConcurrentLoadSync() ConcurrentLoadContext context = new ConcurrentLoadContext( providerFactory: SqlClientFactory.Instance, connectionString: DataTestUtility.TcpConnStr, - mode: ConcurrentLoadContext.Mode.Async, + mode: ConcurrentLoadContext.Mode.Sync, warmupSeconds: 1, executionSeconds: 60, threadCount: Environment.ProcessorCount * 4 @@ -304,337 +301,5 @@ public static async Task TestConcurrentLoadAsync() Assert.True(average > 0); Assert.True(stdDeviation != 0); } - - public class ConcurrentLoadContext - { - public enum Mode - { - Sync, - Async, - } - - public sealed class Category - { - public int Id; - public string Description; - } - - private readonly DbProviderFactory _providerFactory; - private readonly string _connectionString; - private readonly string _query; - private readonly int _warmupSeconds; - private readonly int _executionSeconds; - private readonly Mode _mode; - - private Func _start; - private Func _stop; - private Func _work; - - private int _counter; - private int _totalTransactions; - private int _threadCount; - private int _running; - private List _results; - private DateTime _startTime; - private DateTime _stopTime; - - public ConcurrentLoadContext(DbProviderFactory providerFactory, string connectionString, Mode mode, int warmupSeconds, int executionSeconds, int threadCount) - { - _providerFactory = providerFactory; - _connectionString = connectionString; - _threadCount = threadCount; - _warmupSeconds = warmupSeconds; - _executionSeconds = executionSeconds; - _query = "SELECT CategoryID,Description FROM Categories"; - _results = new List(_executionSeconds); - _mode = mode; - _start = Start; - _stop = Stop; - switch (_mode) - { - case Mode.Sync: - _work = DoWorkSync; - break; - case Mode.Async: - _work = DoWorkSync; - break; - default: - throw new ArgumentOutOfRangeException(nameof(mode)); - } - } - - public void IncrementCounter() => Interlocked.Increment(ref _counter); - - public bool IsRunning - { - get => _running == 1; - set => Interlocked.Exchange(ref _running, value ? 1 : 0); - } - - public Task DoWorkSync() - { - while (IsRunning) - { - var results = new List(); - - using (var connection = _providerFactory.CreateConnection()) - { - connection.ConnectionString = _connectionString; - connection.Open(); - - using (var command = connection.CreateCommand()) - { - command.CommandText = _query; - command.Prepare(); - - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - results.Add( - new Category - { - Id = reader.GetInt32(0), - Description = reader.GetString(1) - }); - } - } - } - } - - CheckResults(results); - - IncrementCounter(); - } - - return Task.CompletedTask; - } - - public Task DoWorkSyncCaching() - { - using (var connection = _providerFactory.CreateConnection()) - { - connection.ConnectionString = _connectionString; - connection.Open(); - - using (var command = connection.CreateCommand()) - { - command.CommandText = _query; - command.Prepare(); - - while (IsRunning) - { - var results = new List(); - - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - results.Add( - new Category - { - Id = reader.GetInt32(0), - Description = reader.GetString(1) - }); - } - } - - CheckResults(results); - - IncrementCounter(); - } - } - } - - return Task.CompletedTask; - } - - public async Task DoWorkAsync() - { - while (IsRunning) - { - var results = new List(); - - using (var connection = _providerFactory.CreateConnection()) - { - connection.ConnectionString = _connectionString; - - await connection.OpenAsync(); - - using (var command = connection.CreateCommand()) - { - command.CommandText = _query; - command.Prepare(); - - using (var reader = await command.ExecuteReaderAsync()) - { - while (await reader.ReadAsync()) - { - results.Add( - new Category - { - Id = reader.GetInt32(0), - Description = reader.GetString(1) - }); - } - } - } - } - - CheckResults(results); - - IncrementCounter(); - } - } - - public async Task DoWorkAsyncCaching() - { - using (var connection = _providerFactory.CreateConnection()) - { - connection.ConnectionString = _connectionString; - - await connection.OpenAsync(); - - using (var command = connection.CreateCommand()) - { - command.CommandText = _query; - command.Prepare(); - - while (IsRunning) - { - var results = new List(); - - using (var reader = await command.ExecuteReaderAsync()) - { - while (await reader.ReadAsync()) - { - results.Add( - new Category - { - Id = reader.GetInt32(0), - Description = reader.GetString(1) - }); - } - } - - CheckResults(results); - - IncrementCounter(); - } - } - } - } - - public async Task<(int transactionPerSecond,double average, double stdDeviation)> Run() - { - IsRunning = true; - - await Task.WhenAll(CreateTasks()); - - _results.Sort(); - _results.RemoveAt(0); - _results.RemoveAt(_results.Count - 1); - - (double avg, double stdDev) = CalculateStdDev(_results); - - int totalTps = (int)(_totalTransactions / (_stopTime - _startTime).TotalSeconds); - - return (totalTps, avg, stdDev); - } - - private async Task Start() - { - await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds)); - - Interlocked.Exchange(ref _counter, 0); - - _startTime = DateTime.UtcNow; - var lastDisplay = _startTime; - - while (IsRunning) - { - await Task.Delay(200); - - DateTime now = DateTime.UtcNow; - int tps = (int)(_counter / (now - lastDisplay).TotalSeconds); - - _results.Add(tps); - - lastDisplay = now; - _totalTransactions += Interlocked.Exchange(ref _counter, 0); - } - } - - private async Task Stop() - { - await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds + _executionSeconds)); - Interlocked.Exchange(ref _running, 0); - _stopTime = DateTime.UtcNow; - } - - private IEnumerable CreateTasks() - { - //yield return Task.Run( - // async () => - // { - - // await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds)); - - // Interlocked.Exchange(ref _counter, 0); - - // _startTime = DateTime.UtcNow; - // var lastDisplay = _startTime; - - // while (IsRunning) - // { - // await Task.Delay(200); - - // var now = DateTime.UtcNow; - // var tps = (int)(_counter / (now - lastDisplay).TotalSeconds); - // var remaining = (int)(_executionSeconds - (now - _startTime).TotalSeconds); - - // _results.Add(tps); - - // lastDisplay = now; - // _totalTransactions += Interlocked.Exchange(ref _counter, 0); - // } - // } - // ); - - yield return Task.Run(_start); - - //yield return Task.Run( - // async () => - // { - // await Task.Delay(TimeSpan.FromSeconds(_warmupSeconds + _executionSeconds)); - - // Interlocked.Exchange(ref _running, 0); - - // _stopTime = DateTime.UtcNow; - // }); - - yield return Task.Run(_stop); - - foreach (var task in Enumerable.Range(0, _threadCount) - .Select(_ => Task.Factory.StartNew(_work, TaskCreationOptions.LongRunning).Unwrap())) - { - yield return task; - } - } - - private static void CheckResults(ICollection results) - { - Assert.NotNull(results); - Assert.Equal(8, results.Count); - } - - private static (double, double) CalculateStdDev(ICollection values) - { - double avg = values.Average(); - double sum = values.Sum(d => Math.Pow(d - avg, 2)); - - return (avg, Math.Sqrt(sum / values.Count)); - } - } } } 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 dfaead50f91c..a041436e2a84 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 @@ -7,6 +7,7 @@ Common\System\Collections\DictionaryExtensions.cs + From dd0fe7665c0f23243c863660b9af87b7a34a187f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sat, 20 Apr 2019 13:17:15 +0000 Subject: [PATCH 03/33] Update dependencies from https://github.com/dotnet/core-setup build 20190420.01 (#37057) - Microsoft.NETCore.App - 3.0.0-preview5-27620-01 - Microsoft.NETCore.DotNetHost - 3.0.0-preview5-27620-01 - Microsoft.NETCore.DotNetHostPolicy - 3.0.0-preview5-27620-01 --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5cd1655c1242..dad1729ce93a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,17 +14,17 @@ - + https://github.com/dotnet/core-setup - 490010c3451a44e45f782a019efd736aa490f79c + b9a720984fa4d6454d1c66ae765bc1e34cb1d206 - + https://github.com/dotnet/core-setup - 490010c3451a44e45f782a019efd736aa490f79c + b9a720984fa4d6454d1c66ae765bc1e34cb1d206 - + https://github.com/dotnet/core-setup - 490010c3451a44e45f782a019efd736aa490f79c + b9a720984fa4d6454d1c66ae765bc1e34cb1d206 https://github.com/dotnet/corefx diff --git a/eng/Versions.props b/eng/Versions.props index c7cd4e1b072d..8abbbea57e94 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -37,9 +37,9 @@ 2.2.0-beta.19218.7 1.0.0-beta.19218.7 - 3.0.0-preview5-27618-16 - 3.0.0-preview5-27618-16 - 3.0.0-preview5-27618-16 + 3.0.0-preview5-27620-01 + 3.0.0-preview5-27620-01 + 3.0.0-preview5-27620-01 3.0.0-preview5-27618-74 3.0.0-preview5-27618-74 From 82931c3fa419e0ddbd756288f9bf938d6bc9ad0f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sat, 20 Apr 2019 13:27:50 +0000 Subject: [PATCH 04/33] Update dependencies from https://github.com/dotnet/corefx build 20190419.11 (#37058) - Microsoft.NETCore.Platforms - 3.0.0-preview5.19219.11 --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index dad1729ce93a..53561bbd36ca 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/core-setup b9a720984fa4d6454d1c66ae765bc1e34cb1d206 - + https://github.com/dotnet/corefx - 0a9a366e290aded3e9bf5d082d6beee5ff560177 + c608ddaa2a024dde2510f3c1122c89ba07b4325d https://github.com/dotnet/arcade diff --git a/eng/Versions.props b/eng/Versions.props index 8abbbea57e94..5d19e0ad3469 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,7 +44,7 @@ 3.0.0-preview5-27618-74 3.0.0-preview5-27618-74 - 3.0.0-preview5.19218.11 + 3.0.0-preview5.19219.11 2.1.0-prerelease.19217.2 From 8e2e72b2683a4b4b983b184f1e703a3174b8566c Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Sat, 20 Apr 2019 06:36:43 -0700 Subject: [PATCH 05/33] skip GetAsync_IPv6LinkLocalAddressUri_Success if address is not available (#37051) --- .../tests/FunctionalTests/HttpClientHandlerTest.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs index 997e7b723e1a..968cc090693c 100644 --- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs @@ -248,12 +248,17 @@ public async Task SendAsync_SimpleGet_Success(Uri remoteServer) } [ActiveIssue(22158, TargetFrameworkMonikers.Uap)] - [Fact] + [ConditionalFact] public async Task GetAsync_IPv6LinkLocalAddressUri_Success() { using (HttpClient client = CreateHttpClient()) { var options = new LoopbackServer.Options { Address = TestHelper.GetIPv6LinkLocalAddress() }; + if (options.Address == null) + { + throw new SkipTestException("Unable to find valid IPv6 LL address."); + } + await LoopbackServer.CreateServerAsync(async (server, url) => { _output.WriteLine(url.ToString()); From d5dc8247a8e4d5d070908f896a7714114e75f6ce Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sat, 20 Apr 2019 13:50:37 +0000 Subject: [PATCH 06/33] Update dependencies from https://github.com/dotnet/coreclr build 20190419.73 (#37061) - Microsoft.NET.Sdk.IL - 3.0.0-preview5-27619-73 - Microsoft.NETCore.ILAsm - 3.0.0-preview5-27619-73 - Microsoft.NETCore.Runtime.CoreCLR - 3.0.0-preview5-27619-73 --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 4 ++-- global.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 53561bbd36ca..cc59c598cb78 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/coreclr - b7167889bc94c084527f184f852b867b2a1c1d56 + 6a7bf9c3af1d3d6e78d7247eef07c48c89a57112 - + https://github.com/dotnet/coreclr - b7167889bc94c084527f184f852b867b2a1c1d56 + 6a7bf9c3af1d3d6e78d7247eef07c48c89a57112 - + https://github.com/dotnet/coreclr - b7167889bc94c084527f184f852b867b2a1c1d56 + 6a7bf9c3af1d3d6e78d7247eef07c48c89a57112 diff --git a/eng/Versions.props b/eng/Versions.props index 5d19e0ad3469..0cf45c039b79 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -41,8 +41,8 @@ 3.0.0-preview5-27620-01 3.0.0-preview5-27620-01 - 3.0.0-preview5-27618-74 - 3.0.0-preview5-27618-74 + 3.0.0-preview5-27619-73 + 3.0.0-preview5-27619-73 3.0.0-preview5.19219.11 diff --git a/global.json b/global.json index 3fb2dafa0767..665d9f80341e 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19218.7", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19218.7", - "Microsoft.NET.Sdk.IL": "3.0.0-preview5-27618-74" + "Microsoft.NET.Sdk.IL": "3.0.0-preview5-27619-73" } } From a3be099a835a3425fabbd97925d49aa6570b90b0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sat, 20 Apr 2019 14:00:09 +0000 Subject: [PATCH 07/33] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20190420.1 (#37062) - optimization.windows_nt-x64.IBC.CoreFx - 99.99.99-master-20190420.1 --- eng/Version.Details.xml | 2 +- eng/Versions.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index cc59c598cb78..9d2371020137 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -94,7 +94,7 @@ https://github.com/dotnet/arcade 5e7ce5b394f3477bb0a485a4b761b7742e95be37 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 262f4c4cfae446577e19e7c79b43ad46ba456e56 diff --git a/eng/Versions.props b/eng/Versions.props index 0cf45c039b79..5b3fe0767af6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -48,6 +48,6 @@ 2.1.0-prerelease.19217.2 - 99.99.99-master-20190419.4 + 99.99.99-master-20190420.1 From 8b515adcd4ea0b8233f018f9e87ef946ce0e7c42 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2e0pgs@gmail.com> Date: Sat, 20 Apr 2019 16:40:41 +0100 Subject: [PATCH 08/33] Squash fix for process name. (#36913) Handle long process names on Linux See: https://github.com/2E0PGS/corefx/commit/56e73858adb046b57165eae44af111d64e2fcd98 * add test * update test * update test * address PR feedback * fix alpine ci * fix compilation * add some log for alpine fail * address PR feedback --- .../Diagnostics/ProcessManager.Linux.cs | 9 ++++- .../tests/ProcessTestBase.cs | 14 ++++++-- .../tests/ProcessTests.cs | 34 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) 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 69800f10b0fb..d65e70788b61 100644 --- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs +++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs @@ -128,10 +128,17 @@ internal static ProcessInfo CreateProcessInfo(Interop.procfs.ParsedStat procFsSt { int pid = procFsStat.pid; + // Get long process name if possible, otherwise use a fall back method. + string procName = Path.GetFileName(Process.GetExePath(pid)); + if (string.IsNullOrEmpty(procName)) + { + procName = procFsStat.comm; + } + var pi = new ProcessInfo() { ProcessId = pid, - ProcessName = procFsStat.comm, + ProcessName = procName, BasePriority = (int)procFsStat.nice, VirtualBytes = (long)procFsStat.vsize, WorkingSet = procFsStat.rss * Environment.SystemPageSize, diff --git a/src/System.Diagnostics.Process/tests/ProcessTestBase.cs b/src/System.Diagnostics.Process/tests/ProcessTestBase.cs index 8fc68010c392..9b15ab99324e 100644 --- a/src/System.Diagnostics.Process/tests/ProcessTestBase.cs +++ b/src/System.Diagnostics.Process/tests/ProcessTestBase.cs @@ -100,6 +100,16 @@ protected void StartSleepKillWait(Process p) /// /// protected static bool IsProgramInstalled(string program) + { + return GetProgramPath(program) != null; + } + + /// + /// Return program path + /// + /// + /// + protected static string GetProgramPath(string program) { string path; string pathEnvVar = Environment.GetEnvironmentVariable("PATH"); @@ -113,11 +123,11 @@ protected static bool IsProgramInstalled(string program) path = Path.Combine(subPath, program); if (File.Exists(path)) { - return true; + return path; } } } - return false; + return null; } } } diff --git a/src/System.Diagnostics.Process/tests/ProcessTests.cs b/src/System.Diagnostics.Process/tests/ProcessTests.cs index fe0897f4129b..6a7fa4633b2b 100644 --- a/src/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/System.Diagnostics.Process/tests/ProcessTests.cs @@ -1875,6 +1875,40 @@ public void TestLongProcessIsWorking() Assert.True(p.HasExited); } + [PlatformSpecific(TestPlatforms.AnyUnix)] + [ActiveIssue(37054, TestPlatforms.OSX)] + [Fact] + public void GetProcesses_LongProcessName() + { + string commandName = "sleep"; + + // sleep program doesn't exist on some flavor + // in flavors such as Alpine, sleep is a busybox command which cannot be renamed + if (!IsProgramInstalled(commandName) || IsProgramInstalled("busybox")) + { + return; + } + + string longProcessName = "123456789012345678901234567890"; + string sleepCommandPathFileName = Path.Combine(TestDirectory, longProcessName); + File.Copy(GetProgramPath(commandName), sleepCommandPathFileName); + + // start sleep program and wait for some seconds + using (Process px = Process.Start(new ProcessStartInfo { FileName = sleepCommandPathFileName , Arguments = "30", UseShellExecute = true})) + { + var runninProcesses = Process.GetProcesses(); + try + { + Assert.Contains(runninProcesses, p => p.ProcessName == longProcessName); + } + finally + { + px.Kill(); + px.WaitForExit(); + } + } + } + private string GetCurrentProcessName() { return $"{Process.GetCurrentProcess().ProcessName}.exe"; From 13cd96122c25328a1b180a6289923657180a7b69 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 20 Apr 2019 16:07:52 -0400 Subject: [PATCH 09/33] Add EnumeratorCancellationAttribute (#37064) * Update ChannelReader.ReadAllAsync for EnumeratorCancellationAttribute * Add EnumeratorCancellationAttribute * Address PR feedback --- src/System.Runtime/ref/System.Runtime.cs | 5 ++++ src/System.Runtime/src/System.Runtime.csproj | 1 + .../EnumeratorCancellationAttribute.cs | 14 ++++++++++ .../AttributesTests.netcoreapp.cs | 6 ++++ .../System.Threading.Channels.netcoreapp.cs | 2 +- .../Channels/ChannelReader.netcoreapp.cs | 28 ++++--------------- .../tests/ChannelTestBase.netcoreapp.cs | 6 ++-- 7 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 src/System.Runtime/src/System/Runtime/CompilerServices/EnumeratorCancellationAttribute.cs diff --git a/src/System.Runtime/ref/System.Runtime.cs b/src/System.Runtime/ref/System.Runtime.cs index 1218e1275a51..338abebdcbaf 100644 --- a/src/System.Runtime/ref/System.Runtime.cs +++ b/src/System.Runtime/ref/System.Runtime.cs @@ -6645,6 +6645,11 @@ public partial class DiscardableAttribute : System.Attribute { public DiscardableAttribute() { } } + [System.AttributeUsageAttribute(AttributeTargets.Parameter, Inherited = false)] + public sealed class EnumeratorCancellationAttribute : Attribute + { + public EnumeratorCancellationAttribute() { } + } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method)] public sealed partial class ExtensionAttribute : System.Attribute { diff --git a/src/System.Runtime/src/System.Runtime.csproj b/src/System.Runtime/src/System.Runtime.csproj index e3808c9f01e0..c623d29cfbad 100644 --- a/src/System.Runtime/src/System.Runtime.csproj +++ b/src/System.Runtime/src/System.Runtime.csproj @@ -18,6 +18,7 @@ + diff --git a/src/System.Runtime/src/System/Runtime/CompilerServices/EnumeratorCancellationAttribute.cs b/src/System.Runtime/src/System/Runtime/CompilerServices/EnumeratorCancellationAttribute.cs new file mode 100644 index 000000000000..8121d72c9c1b --- /dev/null +++ b/src/System.Runtime/src/System/Runtime/CompilerServices/EnumeratorCancellationAttribute.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.Runtime.CompilerServices +{ + [System.AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + public sealed class EnumeratorCancellationAttribute : Attribute + { + public EnumeratorCancellationAttribute() + { + } + } +} diff --git a/src/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.netcoreapp.cs b/src/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.netcoreapp.cs index 43a1d916de00..089b81d990cb 100644 --- a/src/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.netcoreapp.cs +++ b/src/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.netcoreapp.cs @@ -29,5 +29,11 @@ public static void IsReadOnlyAttributeTests() { new IsReadOnlyAttribute(); } + + [Fact] + public static void EnumeratorCancellationAttributeTests() + { + new EnumeratorCancellationAttribute(); + } } } diff --git a/src/System.Threading.Channels/ref/System.Threading.Channels.netcoreapp.cs b/src/System.Threading.Channels/ref/System.Threading.Channels.netcoreapp.cs index b72974750480..a0c788255dd0 100644 --- a/src/System.Threading.Channels/ref/System.Threading.Channels.netcoreapp.cs +++ b/src/System.Threading.Channels/ref/System.Threading.Channels.netcoreapp.cs @@ -13,6 +13,6 @@ protected ChannelClosedException(System.Runtime.Serialization.SerializationInfo } public abstract partial class ChannelReader { - public virtual System.Collections.Generic.IAsyncEnumerable ReadAllAsync() { throw null; } + public virtual System.Collections.Generic.IAsyncEnumerable ReadAllAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; } } } diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.netcoreapp.cs b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.netcoreapp.cs index f2cc0586924e..ebb54516267c 100644 --- a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.netcoreapp.cs +++ b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.netcoreapp.cs @@ -3,42 +3,26 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; +using System.Runtime.CompilerServices; namespace System.Threading.Channels { public abstract partial class ChannelReader { /// Creates an that enables reading all of the data from the channel. + /// The to use to cancel the enumeration. /// /// Each call that returns true will read the next item out of the channel. /// will return false once no more data is or will ever be available to read. /// /// The created async enumerable. - public virtual IAsyncEnumerable ReadAllAsync() => new AsyncEnumerable(this); - - /// Provides the async enumerable implementation for . - private sealed class AsyncEnumerable : IAsyncEnumerable + public virtual async IAsyncEnumerable ReadAllAsync([EnumeratorCancellation] CancellationToken cancellationToken = default) { - /// The reader instance whose contents should be read. - private readonly ChannelReader _reader; - - /// Initializes the enumerable. - /// The reader to read. - internal AsyncEnumerable(ChannelReader reader) - { - Debug.Assert(reader != null); - _reader = reader; - } - - async IAsyncEnumerator IAsyncEnumerable.GetAsyncEnumerator(CancellationToken cancellationToken) + while (await WaitToReadAsync(cancellationToken).ConfigureAwait(false)) { - while (await _reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false)) + while (TryRead(out T item)) { - while (_reader.TryRead(out T item)) - { - yield return item; - } + yield return item; } } } diff --git a/src/System.Threading.Channels/tests/ChannelTestBase.netcoreapp.cs b/src/System.Threading.Channels/tests/ChannelTestBase.netcoreapp.cs index 2322d695afcf..278721fe1393 100644 --- a/src/System.Threading.Channels/tests/ChannelTestBase.netcoreapp.cs +++ b/src/System.Threading.Channels/tests/ChannelTestBase.netcoreapp.cs @@ -160,7 +160,7 @@ public async Task ReadAllAsync_MultipleEnumerationsToEnd() await e.DisposeAsync(); e = enumerable.GetAsyncEnumerator(); - Assert.NotSame(enumerable, e); + Assert.Same(enumerable, e); Assert.False(await e.MoveNextAsync()); Assert.False(await e.MoveNextAsync()); @@ -252,7 +252,7 @@ public async Task ReadAllAsync_CanceledBeforeMoveNextAsync_Throws(bool dataAvail var cts = new CancellationTokenSource(); cts.Cancel(); - IAsyncEnumerator e = c.Reader.ReadAllAsync().GetAsyncEnumerator(cts.Token); + IAsyncEnumerator e = c.Reader.ReadAllAsync(cts.Token).GetAsyncEnumerator(); ValueTask vt = e.MoveNextAsync(); Assert.True(vt.IsCompleted); Assert.False(vt.IsCompletedSuccessfully); @@ -266,7 +266,7 @@ public async Task ReadAllAsync_CanceledAfterMoveNextAsync_Throws() Channel c = CreateChannel(); var cts = new CancellationTokenSource(); - IAsyncEnumerator e = c.Reader.ReadAllAsync().GetAsyncEnumerator(cts.Token); + IAsyncEnumerator e = c.Reader.ReadAllAsync(cts.Token).GetAsyncEnumerator(); ValueTask vt = e.MoveNextAsync(); Assert.False(vt.IsCompleted); From 4f001095dfc7fd8d56b8a4d3b6aa4b66fc319cd3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sun, 21 Apr 2019 13:04:18 +0000 Subject: [PATCH 10/33] Update dependencies from https://github.com/dotnet/core-setup build 20190420.10 (#37073) - Microsoft.NETCore.App - 3.0.0-preview5-27620-10 - Microsoft.NETCore.DotNetHost - 3.0.0-preview5-27620-10 - Microsoft.NETCore.DotNetHostPolicy - 3.0.0-preview5-27620-10 --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9d2371020137..f7a8f64c6683 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,17 +14,17 @@ - + https://github.com/dotnet/core-setup - b9a720984fa4d6454d1c66ae765bc1e34cb1d206 + 3907f75cb6a0489f8dc6f72169146c3d79d20d41 - + https://github.com/dotnet/core-setup - b9a720984fa4d6454d1c66ae765bc1e34cb1d206 + 3907f75cb6a0489f8dc6f72169146c3d79d20d41 - + https://github.com/dotnet/core-setup - b9a720984fa4d6454d1c66ae765bc1e34cb1d206 + 3907f75cb6a0489f8dc6f72169146c3d79d20d41 https://github.com/dotnet/corefx diff --git a/eng/Versions.props b/eng/Versions.props index 5b3fe0767af6..ece2e6f3c4bd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -37,9 +37,9 @@ 2.2.0-beta.19218.7 1.0.0-beta.19218.7 - 3.0.0-preview5-27620-01 - 3.0.0-preview5-27620-01 - 3.0.0-preview5-27620-01 + 3.0.0-preview5-27620-10 + 3.0.0-preview5-27620-10 + 3.0.0-preview5-27620-10 3.0.0-preview5-27619-73 3.0.0-preview5-27619-73 From 54fda3108a2d1f99ee915134628fa993334b7d89 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sun, 21 Apr 2019 13:13:57 +0000 Subject: [PATCH 11/33] Update dependencies from https://github.com/dotnet/corefx build 20190420.3 (#37074) - Microsoft.NETCore.Platforms - 3.0.0-preview5.19220.3 --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f7a8f64c6683..ceca81033911 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/core-setup 3907f75cb6a0489f8dc6f72169146c3d79d20d41 - + https://github.com/dotnet/corefx - c608ddaa2a024dde2510f3c1122c89ba07b4325d + 8b515adcd4ea0b8233f018f9e87ef946ce0e7c42 https://github.com/dotnet/arcade diff --git a/eng/Versions.props b/eng/Versions.props index ece2e6f3c4bd..e0e45e5a8651 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,7 +44,7 @@ 3.0.0-preview5-27619-73 3.0.0-preview5-27619-73 - 3.0.0-preview5.19219.11 + 3.0.0-preview5.19220.3 2.1.0-prerelease.19217.2 From 87080f9cf74b95fef2d61cce4058664d9de8da79 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sun, 21 Apr 2019 13:30:35 +0000 Subject: [PATCH 12/33] Update dependencies from https://github.com/dotnet/coreclr build 20190420.72 (#37075) - Microsoft.NET.Sdk.IL - 3.0.0-preview5-27620-72 - Microsoft.NETCore.ILAsm - 3.0.0-preview5-27620-72 - Microsoft.NETCore.Runtime.CoreCLR - 3.0.0-preview5-27620-72 --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 4 ++-- global.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ceca81033911..65302a9c09d8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/coreclr - 6a7bf9c3af1d3d6e78d7247eef07c48c89a57112 + bb40344e36c19b142969e6f29824a395c7a14921 - + https://github.com/dotnet/coreclr - 6a7bf9c3af1d3d6e78d7247eef07c48c89a57112 + bb40344e36c19b142969e6f29824a395c7a14921 - + https://github.com/dotnet/coreclr - 6a7bf9c3af1d3d6e78d7247eef07c48c89a57112 + bb40344e36c19b142969e6f29824a395c7a14921 diff --git a/eng/Versions.props b/eng/Versions.props index e0e45e5a8651..6a36762b2e1f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -41,8 +41,8 @@ 3.0.0-preview5-27620-10 3.0.0-preview5-27620-10 - 3.0.0-preview5-27619-73 - 3.0.0-preview5-27619-73 + 3.0.0-preview5-27620-72 + 3.0.0-preview5-27620-72 3.0.0-preview5.19220.3 diff --git a/global.json b/global.json index 665d9f80341e..1ce2f550fbca 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19218.7", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19218.7", - "Microsoft.NET.Sdk.IL": "3.0.0-preview5-27619-73" + "Microsoft.NET.Sdk.IL": "3.0.0-preview5-27620-72" } } From 9fc114f23b9579f9a4b8832bffa17e1c3b0c1448 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sun, 21 Apr 2019 13:33:13 +0000 Subject: [PATCH 13/33] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20190421.1 (#37076) - optimization.windows_nt-x64.IBC.CoreFx - 99.99.99-master-20190421.1 --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 65302a9c09d8..3763fb44fe8f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -94,9 +94,9 @@ https://github.com/dotnet/arcade 5e7ce5b394f3477bb0a485a4b761b7742e95be37 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 262f4c4cfae446577e19e7c79b43ad46ba456e56 + f0801f43ca046737efb933d07b741838f5197e19 diff --git a/eng/Versions.props b/eng/Versions.props index 6a36762b2e1f..1da918ab0d75 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -48,6 +48,6 @@ 2.1.0-prerelease.19217.2 - 99.99.99-master-20190420.1 + 99.99.99-master-20190421.1 From 0ac3306ffe66327ec6360694579fe1fe786816e1 Mon Sep 17 00:00:00 2001 From: Steve MacLean Date: Sun, 21 Apr 2019 11:09:43 -0400 Subject: [PATCH 14/33] Fix DefaultLoadContextTest (#37071) Move clear of olc.LoadedFromContext earlier before System.Runtime is loaded. --- .../tests/DefaultContext/DefaultLoadContextTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs b/src/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs index 13aae6f8a4f4..e391b211dffa 100644 --- a/src/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs +++ b/src/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs @@ -248,6 +248,8 @@ public void DefaultContextOverrideTPA() var asmTargetAsm = olc.LoadFromAssemblyPath(_assemblyPath); var loadedContext = AssemblyLoadContext.GetLoadContext(asmTargetAsm); + olc.LoadedFromContext = false; + // LoadContext of the assembly should be the custom context and not DefaultContext Assert.NotEqual(lcDefault, olc); Assert.Equal(olc, loadedContext); @@ -260,7 +262,6 @@ public void DefaultContextOverrideTPA() // Load System.Runtime - since this is on TPA, it should get resolved from our custom load context // since the Load method has been implemented to override TPA assemblies. var assemblyName = "System.Runtime, Version=4.0.0.0"; - olc.LoadedFromContext = false; Assembly asmLoaded = (Assembly)method.Invoke(null, new object[] {assemblyName}); loadedContext = AssemblyLoadContext.GetLoadContext(asmLoaded); From 431f6557d0089e07c953934583e1decca3c90831 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Sun, 21 Apr 2019 09:13:09 -0700 Subject: [PATCH 15/33] Add Dictionary support to JsonSerializer (#37070) * Add Dictionary support to JsonSerializer This partially addresses https://github.com/dotnet/corefx/issues/36024. For the intial version, only `Dictionary` is supported. * Refactor * Add more tests --- .../src/System.Text.Json.csproj | 1 + .../Text/Json/Serialization/ClassType.cs | 1 + .../JsonClassInfo.AddProperty.cs | 14 +- .../Text/Json/Serialization/JsonClassInfo.cs | 28 ++- .../Json/Serialization/JsonPropertyInfo.cs | 5 +- .../Serialization/JsonPropertyInfoCommon.cs | 17 ++ .../JsonPropertyInfoNotNullable.cs | 6 + .../Serialization/JsonPropertyInfoNullable.cs | 6 + .../JsonSerializer.Read.HandleArray.cs | 30 +++- .../JsonSerializer.Read.HandleNull.cs | 4 +- .../JsonSerializer.Read.HandleObject.cs | 8 +- .../JsonSerializer.Read.HandleValue.cs | 3 +- .../Json/Serialization/JsonSerializer.Read.cs | 24 ++- .../JsonSerializer.Write.HandleDictionary.cs | 141 +++++++++++++++ .../JsonSerializer.Write.HandleObject.cs | 12 ++ .../Serialization/JsonSerializer.Write.cs | 3 + .../Text/Json/Serialization/ReadStackFrame.cs | 31 +++- .../Text/Json/Serialization/WriteStack.cs | 2 +- .../Json/Serialization/WriteStackFrame.cs | 8 +- .../tests/Serialization/DictionaryTests.cs | 59 +++++++ .../tests/Serialization/Object.ReadTests.cs | 8 + .../TestClasses.SimpleTestClass.cs | 16 +- .../TestClasses.SimpleTestClassWithObject.cs | 16 +- .../tests/Serialization/TestClasses.cs | 167 ++++++++++++++++++ .../tests/System.Text.Json.Tests.csproj | 1 + 25 files changed, 586 insertions(+), 25 deletions(-) create mode 100644 src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs create mode 100644 src/System.Text.Json/tests/Serialization/DictionaryTests.cs diff --git a/src/System.Text.Json/src/System.Text.Json.csproj b/src/System.Text.Json/src/System.Text.Json.csproj index 32b551ad6684..5070433915f0 100644 --- a/src/System.Text.Json/src/System.Text.Json.csproj +++ b/src/System.Text.Json/src/System.Text.Json.csproj @@ -17,6 +17,7 @@ + diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/ClassType.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/ClassType.cs index 030546d4e942..f5fe6ce2c730 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/ClassType.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/ClassType.cs @@ -13,5 +13,6 @@ internal enum ClassType Object = 1, // POCO or rich data type Value = 2, // Data type with single value Enumerable = 3, // IEnumerable + Dictionary = 4, // IDictionary } } diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs index 4f65a1d5a78d..1e5998046863 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs @@ -13,6 +13,16 @@ private JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo propertyInf { JsonPropertyInfo jsonInfo = CreateProperty(propertyType, propertyType, propertyInfo, classType, options); + // Convert interfaces to concrete types. + if (propertyType.IsInterface && jsonInfo.ClassType == ClassType.Dictionary) + { + Type newPropertyType = jsonInfo.ElementClassInfo.GetPolicyProperty().GetConcreteType(propertyType); + if (propertyType != newPropertyType) + { + jsonInfo = CreateProperty(propertyType, newPropertyType, propertyInfo, classType, options); + } + } + if (propertyInfo != null) { _propertyRefs.Add(new PropertyRef(GetKey(jsonInfo.CompareName), jsonInfo)); @@ -30,7 +40,7 @@ internal JsonPropertyInfo CreateProperty(Type declaredPropertyType, Type runtime { Type collectionElementType = null; ClassType propertyClassType = GetClassType(runtimePropertyType); - if (propertyClassType == ClassType.Enumerable) + if (propertyClassType == ClassType.Enumerable || propertyClassType == ClassType.Dictionary) { collectionElementType = GetElementType(runtimePropertyType); // todo: if collectionElementType is object, create loosely-typed collection (JsonArray). @@ -45,8 +55,6 @@ internal JsonPropertyInfo CreateProperty(Type declaredPropertyType, Type runtime } else { - // For now we only support polymorphism with base type == typeof(object). - Debug.Assert(declaredPropertyType == runtimePropertyType || declaredPropertyType == typeof(object)); propertyInfoClassType = typeof(JsonPropertyInfoNotNullable<,,>).MakeGenericType(parentClassType, declaredPropertyType, runtimePropertyType); } diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs index 3baecf8052bb..c97b0f6d2602 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs @@ -111,13 +111,17 @@ internal JsonClassInfo(Type type, JsonSerializerOptions options) } } } - else if (ClassType == ClassType.Enumerable) + else if (ClassType == ClassType.Enumerable || ClassType == ClassType.Dictionary) { // Add a single property that maps to the class type so we can have policies applied. - AddProperty(type, propertyInfo : null, type, options); + JsonPropertyInfo jsonPropertyInfo = AddProperty(type, propertyInfo: null, type, options); + + // Use the type from the property policy to get any late-bound concrete types (from an interface like IDictionary). + CreateObject = options.ClassMaterializerStrategy.CreateConstructor(jsonPropertyInfo.RuntimePropertyType); // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies. Type elementType = GetElementType(type); + ElementClassInfo = options.GetOrAddClass(elementType); } else if (ClassType == ClassType.Value) @@ -311,9 +315,18 @@ public static Type GetElementType(Type propertyType) elementType = propertyType.GetElementType(); if (elementType == null) { + Type[] args = propertyType.GetGenericArguments(); + if (propertyType.IsGenericType) { - elementType = propertyType.GetGenericArguments()[0]; + if (GetClassType(propertyType) == ClassType.Dictionary) + { + elementType = args[1]; + } + else + { + elementType = args[0]; + } } else { @@ -335,12 +348,19 @@ internal static ClassType GetClassType(Type type) type = Nullable.GetUnderlyingType(type); } - // A Type is considered a value if it implements IConvertible. + // A Type is considered a value if it implements IConvertible or is a DateTimeOffset. if (typeof(IConvertible).IsAssignableFrom(type) || type == typeof(DateTimeOffset)) { return ClassType.Value; } + if (typeof(IDictionary).IsAssignableFrom(type) || + (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IDictionary<,>) + || type.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>)))) + { + return ClassType.Dictionary; + } + if (typeof(IEnumerable).IsAssignableFrom(type)) { return ClassType.Enumerable; diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs index 448f5eb220fb..f40258686284 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs @@ -62,7 +62,7 @@ internal JsonPropertyInfo( ClassType = JsonClassInfo.GetClassType(runtimePropertyType); if (elementType != null) { - Debug.Assert(ClassType == ClassType.Enumerable); + Debug.Assert(ClassType == ClassType.Enumerable || ClassType == ClassType.Dictionary); ElementClassInfo = options.GetOrAddClass(elementType); } @@ -251,12 +251,15 @@ internal TAttribute GetAttribute() where TAttribute : Attribute internal abstract IList CreateConverterList(); + internal abstract Type GetConcreteType(Type interfaceType); + internal abstract void Read(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader); internal abstract void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader); internal abstract void SetValueAsObject(object obj, object value, JsonSerializerOptions options); internal abstract void Write(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer); + internal abstract void WriteDictionary(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer); internal abstract void WriteEnumerable(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer); } } diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoCommon.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoCommon.cs index b7365a8f7aea..f99150d10145 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoCommon.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoCommon.cs @@ -53,6 +53,11 @@ internal JsonPropertyInfoCommon( _isPropertyPolicy = true; HasGetter = true; HasSetter = true; + + if (ClassType == ClassType.Dictionary) + { + ValueConverter = DefaultConverters.s_converter; + } } GetPolicies(options); @@ -90,5 +95,17 @@ internal override IList CreateConverterList() { return new List(); } + + // Map interfaces to a well-known implementation. + internal override Type GetConcreteType(Type interfaceType) + { + if (interfaceType.IsAssignableFrom(typeof(IDictionary)) || + interfaceType.IsAssignableFrom(typeof(IReadOnlyDictionary))) + { + return typeof(Dictionary); + } + + return interfaceType; + } } } diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs index ce4a94fcda26..6dfea95e9009 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.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.Collections.Generic; using System.Diagnostics; using System.Reflection; @@ -127,6 +128,11 @@ internal override void Write(JsonSerializerOptions options, ref WriteStackFrame } } + internal override void WriteDictionary(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer) + { + JsonSerializer.WriteDictionary(ValueConverter, options, ref current, writer); + } + internal override void WriteEnumerable(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer) { if (ValueConverter != null) diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs index 44cc4365b673..a3a31d09c6da 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.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.Collections.Generic; using System.Diagnostics; using System.Reflection; @@ -125,6 +126,11 @@ internal override void Write(JsonSerializerOptions options, ref WriteStackFrame } } + internal override void WriteDictionary(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer) + { + JsonSerializer.WriteDictionary(ValueConverter, options, ref current, writer); + } + internal override void WriteEnumerable(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer) { if (ValueConverter != null) diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs index ebd9fef785fd..ab2efb34d9b7 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs @@ -16,7 +16,9 @@ private static void HandleStartArray( ref Utf8JsonReader reader, ref ReadStack state) { - JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; + JsonPropertyInfo jsonPropertyInfo; + + jsonPropertyInfo = state.Current.JsonPropertyInfo; bool skip = jsonPropertyInfo != null && !jsonPropertyInfo.ShouldDeserialize; if (skip || state.Current.Skip()) @@ -175,6 +177,16 @@ internal static void ApplyObjectToEnumerable(object value, JsonSerializerOptions ((IList)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue, options)).Add(value); } } + else if (frame.IsDictionary()) + { + ((IDictionary)frame.ReturnValue).Add(frame.KeyName, value); + } + else if (frame.IsPropertyADictionary()) + { + Debug.Assert(frame.JsonPropertyInfo != null); + Debug.Assert(frame.ReturnValue != null); + frame.JsonPropertyInfo.SetValueAsObject(frame.ReturnValue, value, options); + } else { Debug.Assert(frame.JsonPropertyInfo != null); @@ -183,7 +195,10 @@ internal static void ApplyObjectToEnumerable(object value, JsonSerializerOptions } // If this method is changed, also change ApplyObjectToEnumerable. - internal static void ApplyValueToEnumerable(ref TProperty value, JsonSerializerOptions options, ref ReadStackFrame frame) + internal static void ApplyValueToEnumerable( + ref TProperty value, + JsonSerializerOptions options, + ref ReadStackFrame frame) { if (frame.IsEnumerable()) { @@ -209,6 +224,17 @@ internal static void ApplyValueToEnumerable(ref TProperty value, Json ((IList)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue, options)).Add(value); } } + else if (frame.IsDictionary()) + { + // todo: use TryAdd and throw JsonReaderException + ((IDictionary)frame.ReturnValue).Add(frame.KeyName, value); + } + else if (frame.IsPropertyADictionary()) + { + Debug.Assert(frame.JsonPropertyInfo != null); + Debug.Assert(frame.ReturnValue != null); + ((IDictionary)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue, options)).Add(frame.KeyName, value); + } else { Debug.Assert(frame.JsonPropertyInfo != null); diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs index 6f1d136fb1a5..c4ea0046def1 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs @@ -30,13 +30,13 @@ private static bool HandleNull(ref Utf8JsonReader reader, ref ReadStack state, J ThrowHelper.ThrowJsonReaderException_DeserializeCannotBeNull(reader, state); } - if (state.Current.IsEnumerable()) + if (state.Current.IsEnumerable() || state.Current.IsDictionary()) { ApplyObjectToEnumerable(null, options, ref state.Current); return false; } - if (state.Current.IsPropertyEnumerable()) + if (state.Current.IsPropertyEnumerable() || state.Current.IsPropertyADictionary()) { state.Current.JsonPropertyInfo.ApplyNullValue(options, ref state); return false; diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.cs index c5dd88dd2b89..1289b49deec7 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.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; - namespace System.Text.Json.Serialization { public static partial class JsonSerializer @@ -17,7 +15,11 @@ private static void HandleStartObject(JsonSerializerOptions options, ref ReadSta return; } - if (state.Current.IsEnumerable() || state.Current.IsPropertyEnumerable()) + if (state.Current.IsDictionary()) + { + // Fall through and treat as a return value. + } + else if (state.Current.IsEnumerable() || state.Current.IsPropertyEnumerable() || state.Current.IsPropertyADictionary()) { // An array of objects either on the current property or on a list Type objType = state.Current.GetElementType(); diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleValue.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleValue.cs index 263e4ae08f87..51b51aa447e5 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleValue.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleValue.cs @@ -19,7 +19,8 @@ private static bool HandleValue(JsonTokenType tokenType, JsonSerializerOptions o jsonPropertyInfo = state.Current.JsonClassInfo.CreatePolymorphicProperty(jsonPropertyInfo, typeof(object), options); } - bool lastCall = (!state.Current.IsEnumerable() && !state.Current.IsPropertyEnumerable() && state.Current.ReturnValue == null); + bool lastCall = (!state.Current.IsProcessingEnumerableOrDictionary() && state.Current.ReturnValue == null); + jsonPropertyInfo.Read(tokenType, options, ref state, ref reader); return lastCall; } diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.cs index e31204546eca..3635039a1856 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Buffers; +using System.Collections.Generic; using System.Diagnostics; namespace System.Text.Json.Serialization @@ -42,13 +43,28 @@ private static void ReadCore( Debug.Assert(state.Current.JsonClassInfo != default); ReadOnlySpan propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; - state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(options, propertyName, ref state.Current); - if (state.Current.JsonPropertyInfo == null) + + if (state.Current.IsDictionary()) { - state.Current.JsonPropertyInfo = s_missingProperty; + string keyName = reader.GetString(); + if (options.DictionaryKeyPolicy != null) + { + keyName = options.DictionaryKeyPolicy.ConvertName(keyName); + } + + state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetPolicyProperty(); + state.Current.KeyName = keyName; } + else + { + state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(options, propertyName, ref state.Current); + if (state.Current.JsonPropertyInfo == null) + { + state.Current.JsonPropertyInfo = s_missingProperty; + } - state.Current.PropertyIndex++; + state.Current.PropertyIndex++; + } } } else if (tokenType == JsonTokenType.StartObject) diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs new file mode 100644 index 000000000000..d826a6851720 --- /dev/null +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.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.Buffers; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.Json.Serialization.Policies; + +namespace System.Text.Json.Serialization +{ + public static partial class JsonSerializer + { + private static bool HandleDictionary( + JsonClassInfo elementClassInfo, + JsonSerializerOptions options, + Utf8JsonWriter writer, + ref WriteStack state) + { + Debug.Assert(state.Current.JsonPropertyInfo.ClassType == ClassType.Dictionary); + + JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; + if (!jsonPropertyInfo.ShouldSerialize) + { + // Ignore writing this property. + return true; + } + + if (state.Current.Enumerator == null) + { + IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue, options); + + if (enumerable == null) + { + // Write a null object or enumerable. + writer.WriteNull(jsonPropertyInfo.Name); + return true; + } + + state.Current.Enumerator = enumerable.GetEnumerator(); + + if (jsonPropertyInfo.Name == null) + { + writer.WriteStartObject(); + } + else + { + writer.WriteStartObject(jsonPropertyInfo.Name); + } + } + + if (state.Current.Enumerator.MoveNext()) + { + // Check for polymorphism. + if (elementClassInfo.ClassType == ClassType.Unknown) + { + //todo:test + object currentValue = ((IDictionaryEnumerator)(state.Current.Enumerator)).Entry; + GetRuntimeClassInfo(currentValue, ref elementClassInfo, options); + } + + if (elementClassInfo.ClassType == ClassType.Value) + { + elementClassInfo.GetPolicyProperty().WriteDictionary(options, ref state.Current, writer); + } + else if (state.Current.Enumerator.Current == null) + { + writer.WriteNull(jsonPropertyInfo.Name); + } + else + { + // An object or another enumerator requires a new stack frame. + object nextValue = state.Current.Enumerator.Current; + state.Push(elementClassInfo, nextValue); + } + + return false; + } + + // We are done enumerating. + writer.WriteEndObject(); + + state.Current.EndDictionary(); + + return true; + } + + internal static void WriteDictionary( + JsonValueConverter converter, + JsonSerializerOptions options, + ref WriteStackFrame current, + Utf8JsonWriter writer) + { + if (converter == null) + { + return; + } + + Debug.Assert(current.Enumerator != null); + + string key; + TProperty value; + if (current.Enumerator is IEnumerator> enumerator) + { + // Avoid boxing for strongly-typed enumerators such as returned from IDictionary + value = enumerator.Current.Value; + key = enumerator.Current.Key; + } + else + { + // Todo: support non-generic Dictionary here (IDictionaryEnumerator) + throw new NotSupportedException(); + } + + if (value == null) + { + writer.WriteNull(key); + } + else + { + byte[] pooledKey = null; + byte[] utf8Key = Encoding.UTF8.GetBytes(key); + int length = JsonWriterHelper.GetMaxEscapedLength(utf8Key.Length, 0); + + Span escapedKey = length <= JsonConstants.StackallocThreshold ? + stackalloc byte[length] : + (pooledKey = ArrayPool.Shared.Rent(length)); + + JsonWriterHelper.EscapeString(utf8Key, escapedKey, 0, out int written); + + converter.Write(escapedKey.Slice(0, written), value, writer); + + if (pooledKey != null) + { + ArrayPool.Shared.Return(pooledKey); + } + } + } + } +} diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleObject.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleObject.cs index 17c5c1c21dc8..8cddfd78f5af 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleObject.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleObject.cs @@ -93,6 +93,18 @@ private static bool HandleObject( return endOfEnumerable; } + // A property that returns a dictionary keeps the same stack frame. + if (jsonPropertyInfo.ClassType == ClassType.Dictionary) + { + bool endOfEnumerable = HandleDictionary(jsonPropertyInfo.ElementClassInfo, options, writer, ref state); + if (endOfEnumerable) + { + state.Current.NextProperty(); + } + + return endOfEnumerable; + } + // A property that returns an object. if (!obtainedValue) { diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.cs index 1913e739a8af..ccbac22d2dda 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.cs @@ -37,6 +37,9 @@ private static bool Write( case ClassType.Object: finishedSerializing = WriteObject(options, writer, ref state); break; + case ClassType.Dictionary: + finishedSerializing = HandleDictionary(current.JsonClassInfo.ElementClassInfo, options, writer, ref state); + break; default: Debug.Assert(state.Current.JsonClassInfo.ClassType == ClassType.Unknown); diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs index ee8cce374983..946815b949ec 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs @@ -14,6 +14,9 @@ internal struct ReadStackFrame internal object ReturnValue; internal JsonClassInfo JsonClassInfo; + // Support Dictionary + internal string KeyName; + // Current property values internal JsonPropertyInfo JsonPropertyInfo; internal bool PopStackOnEndArray; @@ -32,7 +35,7 @@ internal struct ReadStackFrame internal void Initialize(Type type, JsonSerializerOptions options) { JsonClassInfo = options.GetOrAddClass(type); - if (JsonClassInfo.ClassType == ClassType.Value || JsonClassInfo.ClassType == ClassType.Enumerable) + if (JsonClassInfo.ClassType == ClassType.Value || JsonClassInfo.ClassType == ClassType.Enumerable || JsonClassInfo.ClassType == ClassType.Dictionary) { JsonPropertyInfo = JsonClassInfo.GetPolicyProperty(); } @@ -54,6 +57,12 @@ internal void ResetProperty() PopStackOnEndArray = false; EnumerableCreated = false; TempEnumerableValues = null; + KeyName = null; + } + + internal bool IsProcessingEnumerableOrDictionary() + { + return IsEnumerable() ||IsPropertyEnumerable() || IsDictionary() || IsPropertyADictionary(); } internal bool IsEnumerable() @@ -61,6 +70,11 @@ internal bool IsEnumerable() return JsonClassInfo.ClassType == ClassType.Enumerable; } + internal bool IsDictionary() + { + return JsonClassInfo.ClassType == ClassType.Dictionary; + } + internal bool Skip() { return Drain || ReferenceEquals(JsonPropertyInfo, JsonSerializer.s_missingProperty); @@ -76,6 +90,16 @@ internal bool IsPropertyEnumerable() return false; } + internal bool IsPropertyADictionary() + { + if (JsonPropertyInfo != null) + { + return JsonPropertyInfo.ClassType == ClassType.Dictionary; + } + + return false; + } + public Type GetElementType() { if (IsPropertyEnumerable()) @@ -88,6 +112,11 @@ public Type GetElementType() return JsonClassInfo.ElementClassInfo.Type; } + if (IsDictionary()) + { + return JsonClassInfo.ElementClassInfo.Type; + } + return JsonPropertyInfo.RuntimePropertyType; } diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs index 897923f41b38..4b614a94b418 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs @@ -51,7 +51,7 @@ public void Push(JsonClassInfo nextClassInfo, object nextValue) } else { - Debug.Assert(nextClassInfo.ClassType == ClassType.Object || nextClassInfo.ClassType == ClassType.Unknown); + Debug.Assert(nextClassInfo.ClassType == ClassType.Object || nextClassInfo.ClassType == ClassType.Dictionary || nextClassInfo.ClassType == ClassType.Unknown); Current.PopStackOnEndObject = true; } } diff --git a/src/System.Text.Json/src/System/Text/Json/Serialization/WriteStackFrame.cs b/src/System.Text.Json/src/System/Text/Json/Serialization/WriteStackFrame.cs index a9fc78e834d3..72e31672efbd 100644 --- a/src/System.Text.Json/src/System/Text/Json/Serialization/WriteStackFrame.cs +++ b/src/System.Text.Json/src/System/Text/Json/Serialization/WriteStackFrame.cs @@ -29,7 +29,7 @@ internal struct WriteStackFrame internal void Initialize(Type type, JsonSerializerOptions options) { JsonClassInfo = options.GetOrAddClass(type); - if (JsonClassInfo.ClassType == ClassType.Value || JsonClassInfo.ClassType == ClassType.Enumerable) + if (JsonClassInfo.ClassType == ClassType.Value || JsonClassInfo.ClassType == ClassType.Enumerable || JsonClassInfo.ClassType == ClassType.Dictionary) { JsonPropertyInfo = JsonClassInfo.GetPolicyProperty(); } @@ -51,6 +51,12 @@ internal void EndObject() EndProperty(); } + internal void EndDictionary() + { + Enumerator = null; + EndProperty(); + } + internal void EndArray() { Enumerator = null; diff --git a/src/System.Text.Json/tests/Serialization/DictionaryTests.cs b/src/System.Text.Json/tests/Serialization/DictionaryTests.cs new file mode 100644 index 000000000000..0d984b96cc5a --- /dev/null +++ b/src/System.Text.Json/tests/Serialization/DictionaryTests.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.Collections.Generic; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class DictionaryTests + { + [Fact] + public static void DirectReturn() + { + { + Dictionary obj = JsonSerializer.Parse>(@"{""Hello"":""World"", ""Hello2"":""World2""}"); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.ToString(obj); + Assert.Equal(@"{""Hello"":""World"",""Hello2"":""World2""}", json); + + // Round-trip the json + obj = JsonSerializer.Parse>(json); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + } + + { + IDictionary obj = JsonSerializer.Parse>(@"{""Hello"":""World""}"); + Assert.Equal("World", obj["Hello"]); + + string json = JsonSerializer.ToString(obj); + Assert.Equal(@"{""Hello"":""World""}", json); + + obj = JsonSerializer.Parse>(json); + Assert.Equal("World", obj["Hello"]); + } + + { + IReadOnlyDictionary obj = JsonSerializer.Parse>(@"{""Hello"":""World""}"); + Assert.Equal("World", obj["Hello"]); + + string json = JsonSerializer.ToString(obj); + Assert.Equal(@"{""Hello"":""World""}", json); + + obj = JsonSerializer.Parse>(json); + Assert.Equal("World", obj["Hello"]); + } + } + + [Fact] + public static void ThrowsOnDuplicateKeys() + { + // todo: this should throw a JsonReaderException + Assert.Throws(() => JsonSerializer.Parse>(@"{""Hello"":""World"", ""Hello"":""World""}")); + } + } +} diff --git a/src/System.Text.Json/tests/Serialization/Object.ReadTests.cs b/src/System.Text.Json/tests/Serialization/Object.ReadTests.cs index ae498e5965be..4b41c4b3d2fd 100644 --- a/src/System.Text.Json/tests/Serialization/Object.ReadTests.cs +++ b/src/System.Text.Json/tests/Serialization/Object.ReadTests.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 Xunit; namespace System.Text.Json.Serialization.Tests @@ -48,5 +49,12 @@ public static void ParseUntyped() Assert.Throws(() => JsonSerializer.Parse("[]")); Assert.Throws(() => JsonSerializer.Parse("[]")); } + + [Fact] + public static void ReadClassWithStringToPrimitiveDictionary() + { + TestClassWithStringToPrimitiveDictionary obj = JsonSerializer.Parse(TestClassWithStringToPrimitiveDictionary.s_data); + obj.Verify(); + } } } diff --git a/src/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs b/src/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs index ba35451c3f7f..d5ed0cb6bfd7 100644 --- a/src/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs +++ b/src/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs @@ -52,6 +52,9 @@ public class SimpleTestClass : ITestClass public ICollection MyStringICollectionT { get; set; } public IReadOnlyCollection MyStringIReadOnlyCollectionT { get; set; } public IReadOnlyList MyStringIReadOnlyListT { get; set; } + public Dictionary MyStringToStringDict { get; set; } + public IDictionary MyStringToStringIDict { get; set; } + public IReadOnlyDictionary MyStringToStringIReadOnlyDict { get; set; } public static readonly string s_json = $"{{{s_partialJsonProperties},{s_partialJsonArrays}}}"; public static readonly string s_json_flipped = $"{{{s_partialJsonArrays},{s_partialJsonProperties}}}"; @@ -74,7 +77,10 @@ public class SimpleTestClass : ITestClass @"""MyDecimal"" : 3.3," + @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," + @"""MyDateTimeOffset"" : ""2019-01-30T12:01:02.0000000+01:00""," + - @"""MyEnum"" : 2"; // int by default + @"""MyEnum"" : 2," + // int by default + @"""MyStringToStringDict"" : {""key"" : ""value""}," + + @"""MyStringToStringIDict"" : {""key"" : ""value""}," + + @"""MyStringToStringIReadOnlyDict"" : {""key"" : ""value""}"; private const string s_partialJsonArrays = @"""MyInt16Array"" : [1]," + @@ -150,6 +156,10 @@ public void Initialize() MyStringICollectionT = new string[] { "Hello" }; MyStringIReadOnlyCollectionT = new string[] { "Hello" }; MyStringIReadOnlyListT = new string[] { "Hello" }; + + MyStringToStringDict = new Dictionary { { "key", "value" } }; + MyStringToStringIDict = new Dictionary { { "key", "value" } }; + MyStringToStringIReadOnlyDict = new Dictionary { { "key", "value" } }; } public void Verify() @@ -198,6 +208,10 @@ public void Verify() Assert.Equal("Hello", MyStringICollectionT.First()); Assert.Equal("Hello", MyStringIReadOnlyCollectionT.First()); Assert.Equal("Hello", MyStringIReadOnlyListT[0]); + + Assert.Equal("value", MyStringToStringDict["key"]); + Assert.Equal("value", MyStringToStringIDict["key"]); + Assert.Equal("value", MyStringToStringIReadOnlyDict["key"]); } } } diff --git a/src/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs b/src/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs index f7265932aaa0..1a0ae4d73d66 100644 --- a/src/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs +++ b/src/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs @@ -50,6 +50,9 @@ public class SimpleTestClassWithObject : ITestClass public object MyStringICollectionT { get; set; } public object MyStringIReadOnlyCollectionT { get; set; } public object MyStringIReadOnlyListT { get; set; } + public object MyStringToStringDict { get; set; } + public object MyStringToStringIDict { get; set; } + public object MyStringToStringIReadOnlyDict { get; set; } public static readonly string s_json = @"{" + @@ -92,7 +95,10 @@ public class SimpleTestClassWithObject : ITestClass @"""MyStringIListT"" : [""Hello""]," + @"""MyStringICollectionT"" : [""Hello""]," + @"""MyStringIReadOnlyCollectionT"" : [""Hello""]," + - @"""MyStringIReadOnlyListT"" : [""Hello""]" + + @"""MyStringIReadOnlyListT"" : [""Hello""]," + + @"""MyStringToStringDict"" : {""key"" : ""value""}," + + @"""MyStringToStringIDict"" : {""key"" : ""value""}," + + @"""MyStringToStringIReadOnlyDict"" : {""key"" : ""value""}" + @"}"; public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); @@ -141,6 +147,10 @@ public void Initialize() MyStringICollectionT = new string[] { "Hello" }; MyStringIReadOnlyCollectionT = new string[] { "Hello" }; MyStringIReadOnlyListT = new string[] { "Hello" }; + + MyStringToStringDict = new Dictionary { { "key", "value" } }; + MyStringToStringIDict = new Dictionary { { "key", "value" } }; + MyStringToStringIReadOnlyDict = new Dictionary { { "key", "value" } }; } public void Verify() @@ -187,6 +197,10 @@ public void Verify() Assert.Equal("Hello", ((ICollection)MyStringICollectionT).First()); Assert.Equal("Hello", ((IReadOnlyCollection)MyStringIReadOnlyCollectionT).First()); Assert.Equal("Hello", ((IReadOnlyList)MyStringIReadOnlyListT)[0]); + + Assert.Equal("value", ((Dictionary)MyStringToStringDict)["key"]); + Assert.Equal("value", ((IDictionary)MyStringToStringIDict)["key"]); + Assert.Equal("value", ((IReadOnlyDictionary)MyStringToStringIReadOnlyDict)["key"]); } } } diff --git a/src/System.Text.Json/tests/Serialization/TestClasses.cs b/src/System.Text.Json/tests/Serialization/TestClasses.cs index f6c7195ffe9a..826e1d478a31 100644 --- a/src/System.Text.Json/tests/Serialization/TestClasses.cs +++ b/src/System.Text.Json/tests/Serialization/TestClasses.cs @@ -587,6 +587,173 @@ public void Verify() } } + public class TestClassWithStringToPrimitiveDictionary : ITestClass + { + public Dictionary MyInt32Dict { get; set; } + public Dictionary MyBooleanDict { get; set; } + public Dictionary MySingleDict { get; set; } + public Dictionary MyDoubleDict { get; set; } + public Dictionary MyDateTimeDict { get; set; } + public IDictionary MyInt32IDict { get; set; } + public IDictionary MyBooleanIDict { get; set; } + public IDictionary MySingleIDict { get; set; } + public IDictionary MyDoubleIDict { get; set; } + public IDictionary MyDateTimeIDict { get; set; } + public IReadOnlyDictionary MyInt32IReadOnlyDict { get; set; } + public IReadOnlyDictionary MyBooleanIReadOnlyDict { get; set; } + public IReadOnlyDictionary MySingleIReadOnlyDict { get; set; } + public IReadOnlyDictionary MyDoubleIReadOnlyDict { get; set; } + public IReadOnlyDictionary MyDateTimeIReadOnlyDict { get; set; } + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes( + @"{" + + @"""MyInt32Dict"":{" + + @"""key1"": 1," + + @"""key2"": 2" + + @"}," + + @"""MyBooleanDict"":{" + + @"""key1"": true," + + @"""key2"": false" + + @"}," + + @"""MySingleDict"":{" + + @"""key1"": 1.1," + + @"""key2"": 2.2" + + @"}," + + @"""MyDoubleDict"":{" + + @"""key1"": 3.3," + + @"""key2"": 4.4" + + @"}," + + @"""MyDateTimeDict"":{" + + @"""key1"": ""2019-01-30T12:01:02.0000000""," + + @"""key2"": ""2019-01-30T12:01:02.0000000Z""" + + @"}," + + @"""MyInt32IDict"":{" + + @"""key1"": 1," + + @"""key2"": 2" + + @"}," + + @"""MyBooleanIDict"":{" + + @"""key1"": true," + + @"""key2"": false" + + @"}," + + @"""MySingleIDict"":{" + + @"""key1"": 1.1," + + @"""key2"": 2.2" + + @"}," + + @"""MyDoubleIDict"":{" + + @"""key1"": 3.3," + + @"""key2"": 4.4" + + @"}," + + @"""MyDateTimeIDict"":{" + + @"""key1"": ""2019-01-30T12:01:02.0000000""," + + @"""key2"": ""2019-01-30T12:01:02.0000000Z""" + + @"}," + + @"""MyInt32IReadOnlyDict"":{" + + @"""key1"": 1," + + @"""key2"": 2" + + @"}," + + @"""MyBooleanIReadOnlyDict"":{" + + @"""key1"": true," + + @"""key2"": false" + + @"}," + + @"""MySingleIReadOnlyDict"":{" + + @"""key1"": 1.1," + + @"""key2"": 2.2" + + @"}," + + @"""MyDoubleIReadOnlyDict"":{" + + @"""key1"": 3.3," + + @"""key2"": 4.4" + + @"}," + + @"""MyDateTimeIReadOnlyDict"":{" + + @"""key1"": ""2019-01-30T12:01:02.0000000""," + + @"""key2"": ""2019-01-30T12:01:02.0000000Z""" + + @"}" + + @"}"); + + public void Initialize() + { + MyInt32Dict = new Dictionary { { "key1", 1 }, { "key2", 2 } }; + MyBooleanDict = new Dictionary { { "key1", true }, { "key2", false } }; + MySingleDict = new Dictionary { { "key1", 1.1f }, { "key2", 2.2f } }; + MyDoubleDict = new Dictionary { { "key1", 3.3d }, { "key2", 4.4d } }; + MyDateTimeDict = new Dictionary { { "key1", new DateTime(2019, 1, 30, 12, 1, 2) }, { "key2", new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) } }; + + MyInt32IDict = new Dictionary { { "key1", 1 }, { "key2", 2 } }; + MyBooleanIDict = new Dictionary { { "key1", true }, { "key2", false } }; + MySingleIDict = new Dictionary { { "key1", 1.1f }, { "key2", 2.2f } }; + MyDoubleIDict = new Dictionary { { "key1", 3.3d }, { "key2", 4.4d } }; + MyDateTimeIDict = new Dictionary { { "key1", new DateTime(2019, 1, 30, 12, 1, 2) }, { "key2", new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) } }; + + MyInt32IReadOnlyDict = new Dictionary { { "key1", 1 }, { "key2", 2 } }; + MyBooleanIReadOnlyDict = new Dictionary { { "key1", true }, { "key2", false } }; + MySingleIReadOnlyDict = new Dictionary { { "key1", 1.1f }, { "key2", 2.2f } }; + MyDoubleIReadOnlyDict = new Dictionary { { "key1", 3.3d }, { "key2", 4.4d } }; + MyDateTimeIReadOnlyDict = new Dictionary { { "key1", new DateTime(2019, 1, 30, 12, 1, 2) }, { "key2", new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) } }; + } + + public void Verify() + { + Assert.Equal(1, MyInt32Dict["key1"]); + Assert.Equal(2, MyInt32Dict["key2"]); + Assert.Equal(2, MyInt32Dict.Count); + + Assert.Equal(true, MyBooleanDict["key1"]); + Assert.Equal(false, MyBooleanDict["key2"]); + Assert.Equal(2, MyBooleanDict.Count); + + Assert.Equal(1.1f, MySingleDict["key1"]); + Assert.Equal(2.2f, MySingleDict["key2"]); + Assert.Equal(2, MySingleDict.Count); + + Assert.Equal(3.3d, MyDoubleDict["key1"]); + Assert.Equal(4.4d, MyDoubleDict["key2"]); + Assert.Equal(2, MyDoubleDict.Count); + + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2), MyDateTimeDict["key1"]); + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTimeDict["key2"]); + Assert.Equal(2, MyDateTimeDict.Count); + + Assert.Equal(1, MyInt32IDict["key1"]); + Assert.Equal(2, MyInt32IDict["key2"]); + Assert.Equal(2, MyInt32IDict.Count); + + Assert.Equal(true, MyBooleanIDict["key1"]); + Assert.Equal(false, MyBooleanIDict["key2"]); + Assert.Equal(2, MyBooleanIDict.Count); + + Assert.Equal(1.1f, MySingleIDict["key1"]); + Assert.Equal(2.2f, MySingleIDict["key2"]); + Assert.Equal(2, MySingleIDict.Count); + + Assert.Equal(3.3d, MyDoubleIDict["key1"]); + Assert.Equal(4.4d, MyDoubleIDict["key2"]); + Assert.Equal(2, MyDoubleIDict.Count); + + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2), MyDateTimeIDict["key1"]); + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTimeIDict["key2"]); + Assert.Equal(2, MyDateTimeIDict.Count); + + Assert.Equal(1, MyInt32IReadOnlyDict["key1"]); + Assert.Equal(2, MyInt32IReadOnlyDict["key2"]); + Assert.Equal(2, MyInt32IReadOnlyDict.Count); + + Assert.Equal(true, MyBooleanIReadOnlyDict["key1"]); + Assert.Equal(false, MyBooleanIReadOnlyDict["key2"]); + Assert.Equal(2, MyBooleanIReadOnlyDict.Count); + + Assert.Equal(1.1f, MySingleIReadOnlyDict["key1"]); + Assert.Equal(2.2f, MySingleIReadOnlyDict["key2"]); + Assert.Equal(2, MySingleIReadOnlyDict.Count); + + Assert.Equal(3.3d, MyDoubleIReadOnlyDict["key1"]); + Assert.Equal(4.4d, MyDoubleIReadOnlyDict["key2"]); + Assert.Equal(2, MyDoubleIReadOnlyDict.Count); + + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2), MyDateTimeIReadOnlyDict["key1"]); + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTimeIReadOnlyDict["key2"]); + Assert.Equal(2, MyDateTimeIReadOnlyDict.Count); + } + } + public class SimpleDerivedTestClass : SimpleTestClass { } diff --git a/src/System.Text.Json/tests/System.Text.Json.Tests.csproj b/src/System.Text.Json/tests/System.Text.Json.Tests.csproj index 55b32d14aef5..fee73de090ec 100644 --- a/src/System.Text.Json/tests/System.Text.Json.Tests.csproj +++ b/src/System.Text.Json/tests/System.Text.Json.Tests.csproj @@ -26,6 +26,7 @@ + From b96247e76506e81ff6eb28dd2a14914a59e2a257 Mon Sep 17 00:00:00 2001 From: Steve MacLean Date: Sun, 21 Apr 2019 16:19:00 -0400 Subject: [PATCH 16/33] Add ContextualReflection tests (#37052) * Add ContextualReflection tests --- .../tests/ContextualReflection.cs | 1039 +++++++++++++++++ .../Configurations.props | 8 + .../ContextualReflectionDependency.cs | 59 + ...Test.ContextualReflectionDependency.csproj | 9 + .../tests/System.Runtime.Loader.Tests.csproj | 5 +- 5 files changed, 1119 insertions(+), 1 deletion(-) create mode 100644 src/System.Runtime.Loader/tests/ContextualReflection.cs create mode 100644 src/System.Runtime.Loader/tests/ContextualReflectionDependency/Configurations.props create mode 100644 src/System.Runtime.Loader/tests/ContextualReflectionDependency/ContextualReflectionDependency.cs create mode 100644 src/System.Runtime.Loader/tests/ContextualReflectionDependency/System.Runtime.Loader.Test.ContextualReflectionDependency.csproj diff --git a/src/System.Runtime.Loader/tests/ContextualReflection.cs b/src/System.Runtime.Loader/tests/ContextualReflection.cs new file mode 100644 index 000000000000..ad74e48dc58d --- /dev/null +++ b/src/System.Runtime.Loader/tests/ContextualReflection.cs @@ -0,0 +1,1039 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Loader; +using System.Runtime.Remoting; +using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; +using Xunit; + +namespace System.Runtime.Loader.Tests +{ + class AGenericClass + { + } + + class MockAssembly : Assembly + { + public MockAssembly() {} + } + + public class ContextualReflectionTestFixture : IContextualReflectionTestFixture + { + public AssemblyLoadContext isolatedAlc { get; } + public Assembly isolatedAlcAssembly { get; } + public Type isolatedAlcFixtureType { get; } + public IContextualReflectionTestFixture isolatedAlcFixtureInstance { get; } + + public AssemblyLoadContext defaultAlc { get; } + public Assembly defaultAlcAssembly { get; } + public Type defaultAlcFixtureType { get; } + + public Assembly GetExecutingAssembly() { return Assembly.GetExecutingAssembly(); } + + public Assembly AssemblyLoad(AssemblyName name) { return Assembly.Load(name); } + + public Assembly AssemblyLoad(string name) { return Assembly.Load(name); } + +#pragma warning disable 618 + public Assembly AssemblyLoadWithPartialName(string name) { return Assembly.LoadWithPartialName(name); } +#pragma warning restore 618 + + public Type TypeGetType(string typeName) + { return Type.GetType(typeName); } + + public Type TypeGetType(string typeName, bool throwOnError) + { return Type.GetType(typeName, throwOnError); } + + public Type TypeGetType(string typeName, bool throwOnError, bool ignoreCase) + { return Type.GetType(typeName, throwOnError, ignoreCase); } + + public Type TypeGetType(string typeName, Func assemblyResolver, Func typeResolver) + { return Type.GetType(typeName, assemblyResolver, typeResolver); } + + public Type TypeGetType(string typeName, Func assemblyResolver, Func typeResolver, bool throwOnError) + { return Type.GetType(typeName, assemblyResolver, typeResolver, throwOnError); } + + public Type TypeGetType(string typeName, Func assemblyResolver, Func typeResolver, bool throwOnError, bool ignoreCase) + { return Type.GetType(typeName, assemblyResolver, typeResolver, throwOnError, ignoreCase); } + + public Type AssemblyGetType(Assembly assembly, string typeName) + { return assembly.GetType(typeName); } + + public Type AssemblyGetType(Assembly assembly, string typeName, bool throwOnError) + { return assembly.GetType(typeName, throwOnError); } + + public Type AssemblyGetType(Assembly assembly, string typeName, bool throwOnError, bool ignoreCase) + { return assembly.GetType(typeName, throwOnError, ignoreCase); } + + public ObjectHandle ActivatorCreateInstance(string assemblyName, string typeName) + { return Activator.CreateInstance(assemblyName, typeName); } + + public ObjectHandle ActivatorCreateInstance(string assemblyName, string typeName, object[] activationAttributes) + { return Activator.CreateInstance(assemblyName, typeName, activationAttributes); } + + public ObjectHandle ActivatorCreateInstance(string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + { return Activator.CreateInstance(assemblyName, typeName, ignoreCase, bindingAttr, binder, args, culture, activationAttributes); } + + public ContextualReflectionTestFixture() + { + SetPreConditions(); + + Assembly executingAssembly = Assembly.GetExecutingAssembly(); + AssemblyLoadContext executingAlc = AssemblyLoadContext.GetLoadContext(executingAssembly); + + defaultAlc = AssemblyLoadContext.Default; + defaultAlcAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(executingAssembly.GetName()); + defaultAlcFixtureType = defaultAlcAssembly.GetType("System.Runtime.Loader.Tests.ContextualReflectionTestFixture"); + + if (executingAlc == AssemblyLoadContext.Default) + { + isolatedAlc = new AssemblyLoadContext("Isolated", isCollectible: true); + isolatedAlcAssembly = isolatedAlc.LoadFromAssemblyPath(defaultAlcAssembly.Location); + + isolatedAlcFixtureType = isolatedAlcAssembly.GetType("System.Runtime.Loader.Tests.ContextualReflectionTestFixture"); + + isolatedAlcFixtureInstance = (IContextualReflectionTestFixture) Activator.CreateInstance(isolatedAlcFixtureType); + } + else + { + isolatedAlc = executingAlc; + isolatedAlcAssembly = executingAssembly; + isolatedAlcFixtureType = typeof(ContextualReflectionTestFixture); + isolatedAlcFixtureInstance = this; + } + } + + public void SetPreConditions() + { + AssemblyLoadContext.EnterContextualReflection(null); + } + + public void FixtureSetupAssertions() + { + Assert.NotNull(defaultAlc); + Assert.NotNull(defaultAlcAssembly); + Assert.NotNull(defaultAlcFixtureType); + Assert.NotNull(isolatedAlc); + Assert.NotNull(isolatedAlcAssembly); + Assert.NotNull(isolatedAlcFixtureType); + Assert.NotNull(isolatedAlcFixtureInstance); + + Assert.Equal(defaultAlc, isolatedAlcFixtureInstance.defaultAlc); + Assert.Equal(defaultAlcAssembly, isolatedAlcFixtureInstance.defaultAlcAssembly); + Assert.Equal(defaultAlcFixtureType, isolatedAlcFixtureInstance.defaultAlcFixtureType); + Assert.Equal(isolatedAlc, isolatedAlcFixtureInstance.isolatedAlc); + Assert.Equal(isolatedAlcAssembly, isolatedAlcFixtureInstance.isolatedAlcAssembly); + Assert.Equal(isolatedAlcFixtureType, isolatedAlcFixtureInstance.isolatedAlcFixtureType); + Assert.Equal(isolatedAlcFixtureInstance, isolatedAlcFixtureInstance.isolatedAlcFixtureInstance); + + Assert.Equal("Default", defaultAlc.Name); + Assert.Equal("Isolated", isolatedAlc.Name); + + Assert.NotEqual(defaultAlc, isolatedAlc); + Assert.NotEqual(defaultAlcAssembly, isolatedAlcAssembly); + Assert.NotEqual(defaultAlcFixtureType, isolatedAlcFixtureType); + Assert.NotEqual((IContextualReflectionTestFixture)this, isolatedAlcFixtureInstance); + + Assert.Equal(isolatedAlc, AssemblyLoadContext.GetLoadContext(isolatedAlcFixtureInstance.isolatedAlcAssembly)); + } + } + + public class ContextualReflectionTest : IClassFixture + { + IContextualReflectionTestFixture _fixture; + + public ContextualReflectionTest(ContextualReflectionTestFixture fixture) + { + _fixture = fixture; + _fixture.SetPreConditions(); + } + + void AssertAssemblyEqual(Assembly expected, Assembly actual) + { + Assert.Equal(AssemblyLoadContext.GetLoadContext(expected), AssemblyLoadContext.GetLoadContext(actual)); + Assert.Equal(expected, actual); + } + + [Fact] + void FixtureIsSetupCorrectly() + { + _fixture.FixtureSetupAssertions(); + AssertAssemblyEqual(_fixture.defaultAlcAssembly, _fixture.GetExecutingAssembly()); + AssertAssemblyEqual(_fixture.isolatedAlcAssembly, _fixture.isolatedAlcFixtureInstance.GetExecutingAssembly()); + } + +#region EnterContextualReflectionAndDispose + [Fact] + public void CurrentContextualReflectionContextInitialValueNull() + { + RemoteExecutor.Invoke(() => + { + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + return RemoteExecutor.SuccessExitCode; + }).Dispose(); + } + + [Fact] + void InstanceEnterContextualReflectionRaw() + { + AssemblyLoadContext context; + + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + { + context.EnterContextualReflection(); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + { + context.EnterContextualReflection(); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void StaticEnterContextualReflectionRaw() + { + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + AssemblyLoadContext context = null; + Assembly assembly = null; + { + AssemblyLoadContext.EnterContextualReflection(assembly); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + assembly = _fixture.defaultAlcAssembly; + { + AssemblyLoadContext.EnterContextualReflection(assembly); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + assembly = _fixture.isolatedAlcAssembly; + { + AssemblyLoadContext.EnterContextualReflection(assembly); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void InstanceEnterContextualReflectionRawDispose() + { + AssemblyLoadContext context; + + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + { + var scope = context.EnterContextualReflection(); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + { + var scope = context.EnterContextualReflection(); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void StaticEnterContextualReflectionRawDispose() + { + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + AssemblyLoadContext context = null; + Assembly assembly = null; + { + var scope = AssemblyLoadContext.EnterContextualReflection(assembly); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + assembly = _fixture.defaultAlcAssembly; + { + var scope = AssemblyLoadContext.EnterContextualReflection(assembly); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + assembly = _fixture.isolatedAlcAssembly; + { + var scope = AssemblyLoadContext.EnterContextualReflection(assembly); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void InstanceEnterContextualReflectionUsingBasic() + { + AssemblyLoadContext context; + + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + using (context.EnterContextualReflection()) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + using (context.EnterContextualReflection()) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void StaticEnterContextualReflectionUsingBasic() + { + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + AssemblyLoadContext context = null; + Assembly assembly = null; + using (AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + assembly = _fixture.defaultAlcAssembly; + using (AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + assembly = _fixture.isolatedAlcAssembly; + using (AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void InstanceEnterContextualReflectionUsingNested() + { + AssemblyLoadContext context; + + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + using (context.EnterContextualReflection()) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + AssemblyLoadContext nestedContext = _fixture.isolatedAlc; + using (nestedContext.EnterContextualReflection()) + { + Assert.Equal(nestedContext, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + using (context.EnterContextualReflection()) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + AssemblyLoadContext nestedContext = _fixture.defaultAlc; + using (nestedContext.EnterContextualReflection()) + { + Assert.Equal(nestedContext, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void StaticEnterContextualReflectionUsingNested() + { + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + AssemblyLoadContext context = null; + Assembly assembly = null; + using (AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + AssemblyLoadContext nestedContext = _fixture.isolatedAlc; + using (nestedContext.EnterContextualReflection()) + { + Assert.Equal(nestedContext, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + assembly = _fixture.defaultAlcAssembly; + using (AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + AssemblyLoadContext nestedContext = _fixture.isolatedAlc; + using (nestedContext.EnterContextualReflection()) + { + Assert.Equal(nestedContext, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + assembly = _fixture.isolatedAlcAssembly; + using (AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + AssemblyLoadContext nestedContext = _fixture.isolatedAlc; + using (nestedContext.EnterContextualReflection()) + { + Assert.Equal(nestedContext, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void EnterContextualReflectionUsingNestedImmutableDispose() + { + AssemblyLoadContext context; + + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + using (var scopeDefault = context.EnterContextualReflection()) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + AssemblyLoadContext nestedContext = _fixture.isolatedAlc; + using (var scopeIsolated = nestedContext.EnterContextualReflection()) + { + Assert.Equal(nestedContext, AssemblyLoadContext.CurrentContextualReflectionContext); + + scopeDefault.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + scopeIsolated.Dispose(); + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + scopeDefault.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void InstanceEnterContextualReflectionUsingEarlyDispose() + { + AssemblyLoadContext context; + + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + using (var scope = context.EnterContextualReflection()) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + using (var scope = context.EnterContextualReflection()) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void StaticEnterContextualReflectionUsingEarlyDispose() + { + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + AssemblyLoadContext context = null; + Assembly assembly = null; + using (var scope = AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.defaultAlc; + assembly = _fixture.defaultAlcAssembly; + using (var scope = AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + + context = _fixture.isolatedAlc; + assembly = _fixture.isolatedAlcAssembly; + using (var scope = AssemblyLoadContext.EnterContextualReflection(assembly)) + { + Assert.Equal(context, AssemblyLoadContext.CurrentContextualReflectionContext); + + scope.Dispose(); + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + Assert.Null(AssemblyLoadContext.CurrentContextualReflectionContext); + } + + [Fact] + void EnterContextualReflectionWithMockAssemblyThrows() + { + AssertExtensions.Throws("activating", () => AssemblyLoadContext.EnterContextualReflection(new MockAssembly())); + } +#endregion + +#region Assembly.Load + void AssemblyLoadTestCase(Func func, Assembly nullExpected, Assembly defaultExpected, Assembly isolatedExpected) + { + AssertAssemblyEqual(nullExpected, func()); + + using (_fixture.defaultAlc.EnterContextualReflection()) + { + AssertAssemblyEqual(defaultExpected, func()); + } + + using (_fixture.isolatedAlc.EnterContextualReflection()) + { + AssertAssemblyEqual(isolatedExpected, func()); + } + } + + [Fact] + void AssemblyLoadAssemblyNameMultiLoadedAssemblyDefault() + { + AssemblyName name = _fixture.defaultAlcAssembly.GetName(); + + AssemblyLoadTestCase(() => _fixture.AssemblyLoad(name), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + void AssemblyLoadAssemblyNameMultiLoadedAssemblyIsolated() + { + AssemblyName name = _fixture.defaultAlcAssembly.GetName(); + + AssemblyLoadTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyLoad(name), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + void AssemblyLoadAssemblyNameSharedAssemblyDefault() + { + Assembly sharedAssembly = typeof(IContextualReflectionTestFixture).Assembly; + AssemblyName name = sharedAssembly.GetName(); + + AssemblyLoadTestCase(() => _fixture.AssemblyLoad(name), + sharedAssembly, + sharedAssembly, + sharedAssembly); + } + + [Fact] + void AssemblyLoadAssemblyNameSharedAssemblyIsolated() + { + Assembly sharedAssembly = typeof(IContextualReflectionTestFixture).Assembly; + AssemblyName name = sharedAssembly.GetName(); + + AssemblyLoadTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyLoad(name), + sharedAssembly, + sharedAssembly, + sharedAssembly); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/coreclr/issues/24135")] + void AssemblyLoadStringMultiLoadedAssemblyDefault() + { + string name = _fixture.defaultAlcAssembly.GetName().Name; + + AssemblyLoadTestCase(() => _fixture.AssemblyLoad(name), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + AssemblyLoadTestCase(() => _fixture.AssemblyLoadWithPartialName(name), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/coreclr/issues/24135")] + void AssemblyLoadStringMultiLoadedAssemblyIsolated() + { + string name = _fixture.defaultAlcAssembly.GetName().Name; + + AssemblyLoadTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyLoad(name), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + AssemblyLoadTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyLoadWithPartialName(name), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + void AssemblyLoadStringSharedAssemblyDefault() + { + Assembly sharedAssembly = typeof(IContextualReflectionTestFixture).Assembly; + string name = sharedAssembly.GetName().Name; + + AssemblyLoadTestCase(() => _fixture.AssemblyLoad(name), + sharedAssembly, + sharedAssembly, + sharedAssembly); + } + + [Fact] + void AssemblyLoadStringSharedAssemblyIsolated() + { + Assembly sharedAssembly = typeof(IContextualReflectionTestFixture).Assembly; + string name = sharedAssembly.GetName().Name; + + AssemblyLoadTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyLoad(name), + sharedAssembly, + sharedAssembly, + sharedAssembly); + } +#endregion + +#region Type.GetType + void TypeGetTypeTestCase(Func func, Assembly nullExpected, Assembly defaultExpected, Assembly isolatedExpected) + { + AssertAssemblyEqual(nullExpected, func().Assembly); + + using (_fixture.defaultAlc.EnterContextualReflection()) + { + AssertAssemblyEqual(defaultExpected, func().Assembly); + } + + using (_fixture.isolatedAlc.EnterContextualReflection()) + { + AssertAssemblyEqual(isolatedExpected, func().Assembly); + } + } + + [Fact] + void TypeGetTypeStringSharedAssemblyDefault() + { + Assembly assembly = typeof(IContextualReflectionTestFixture).Assembly; + string typeName = typeof(IContextualReflectionTestFixture).AssemblyQualifiedName; + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, throwOnError:false), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, throwOnError:false, ignoreCase:true), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, null, null), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, null, null, throwOnError:false), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, null, null, throwOnError:false, ignoreCase:true), + assembly, + assembly, + assembly); + } + + [Fact] + void TypeGetTypeStringSharedAssemblyIsolated() + { + Assembly assembly = typeof(IContextualReflectionTestFixture).Assembly; + string typeName = typeof(IContextualReflectionTestFixture).AssemblyQualifiedName; + + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, throwOnError:false), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, throwOnError:false, ignoreCase:true), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, null, null), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, null, null, throwOnError:false), + assembly, + assembly, + assembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, null, null, throwOnError:false, ignoreCase:true), + assembly, + assembly, + assembly); + } + + [Fact] + void TypeGetTypeStringMultiLoadedAssemblyDefault() + { + string typeName = typeof(ContextualReflectionTestFixture).AssemblyQualifiedName; + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, throwOnError:false), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, throwOnError:false, ignoreCase:true), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, null, null), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, null, null, throwOnError:false), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.TypeGetType(typeName, null, null, throwOnError:false, ignoreCase:true), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + void TypeGetTypeStringMultiLoadedAssemblyIsolated() + { + string typeName = typeof(ContextualReflectionTestFixture).AssemblyQualifiedName; + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, throwOnError:false), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, throwOnError:false, ignoreCase:true), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, null, null), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, null, null, throwOnError:false), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.TypeGetType(typeName, null, null, throwOnError:false, ignoreCase:true), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + +#endregion + +#region Assembly.GetType + void AssemblyGetTypeTestCase(Func func, Assembly nullExpected, Assembly defaultExpected, Assembly isolatedExpected) + { + AssertAssemblyEqual(nullExpected, func().GenericTypeArguments?[0].Assembly); + + using (_fixture.defaultAlc.EnterContextualReflection()) + { + AssertAssemblyEqual(defaultExpected, func().GenericTypeArguments?[0].Assembly); + } + + using (_fixture.isolatedAlc.EnterContextualReflection()) + { + AssertAssemblyEqual(isolatedExpected, func().GenericTypeArguments?[0].Assembly); + } + } + + [Fact] + void AssemblyGetTypeStringSharedAssemblyDefault() + { + Assembly assembly = typeof(IContextualReflectionTestFixture).Assembly; + string typeNameAGenericClass = typeof(AGenericClass<>).FullName; + string typeNameGenericArgument = typeof(IContextualReflectionTestFixture).AssemblyQualifiedName; + string typeName = $"{typeNameAGenericClass}[[{typeNameGenericArgument}]]"; + + AssemblyGetTypeTestCase(() => _fixture.AssemblyGetType(_fixture.defaultAlcAssembly, typeName), + assembly, + assembly, + assembly); + AssemblyGetTypeTestCase(() => _fixture.AssemblyGetType(_fixture.defaultAlcAssembly, typeName, throwOnError:false), + assembly, + assembly, + assembly); + AssemblyGetTypeTestCase(() => _fixture.AssemblyGetType(_fixture.defaultAlcAssembly, typeName, throwOnError:false, ignoreCase:true), + assembly, + assembly, + assembly); + } + + [Fact] + void AssemblyGetTypeStringSharedAssemblyIsolated() + { + Assembly assembly = typeof(IContextualReflectionTestFixture).Assembly; + string typeNameAGenericClass = typeof(AGenericClass<>).FullName; + string typeNameGenericArgument = typeof(IContextualReflectionTestFixture).AssemblyQualifiedName; + string typeName = $"{typeNameAGenericClass}[[{typeNameGenericArgument}]]"; + + AssemblyGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyGetType(_fixture.defaultAlcAssembly, typeName), + assembly, + assembly, + assembly); + AssemblyGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyGetType(_fixture.defaultAlcAssembly, typeName, throwOnError:false), + assembly, + assembly, + assembly); + AssemblyGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyGetType(_fixture.defaultAlcAssembly, typeName, throwOnError:false, ignoreCase:true), + assembly, + assembly, + assembly); + } + + [Fact] + void AssemblyGetTypeStringMultiLoadedAssemblyDefault() + { + string typeNameAGenericClass = typeof(AGenericClass<>).FullName; + string typeNameGenericArgument = typeof(ContextualReflectionTestFixture).AssemblyQualifiedName; + string typeName = $"{typeNameAGenericClass}[[{typeNameGenericArgument}]]"; + + AssemblyGetTypeTestCase(() => _fixture.AssemblyGetType(_fixture.defaultAlcAssembly, typeName), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + AssemblyGetTypeTestCase(() => _fixture.AssemblyGetType(_fixture.defaultAlcAssembly, typeName, throwOnError:false), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + AssemblyGetTypeTestCase(() => _fixture.AssemblyGetType(_fixture.defaultAlcAssembly, typeName, throwOnError:false, ignoreCase:true), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + void AssemblyGetTypeStringMultiLoadedAssemblyIsolated() + { + string typeNameAGenericClass = typeof(AGenericClass<>).FullName; + string typeNameGenericArgument = typeof(ContextualReflectionTestFixture).AssemblyQualifiedName; + string typeName = $"{typeNameAGenericClass}[[{typeNameGenericArgument}]]"; + + AssemblyGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyGetType(_fixture.isolatedAlcAssembly, typeName), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + AssemblyGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyGetType(_fixture.isolatedAlcAssembly, typeName, throwOnError:false), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + + AssemblyGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.AssemblyGetType(_fixture.isolatedAlcAssembly, typeName, throwOnError:false, ignoreCase:true), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } +#endregion + +#region Activator.CreateInstance + [Fact] + void ActivatorCreateInstanceNullMultiLoadedAssemblyDefault() + { + string typeName = typeof(ContextualReflectionTestFixture).FullName; + + TypeGetTypeTestCase(() => _fixture.ActivatorCreateInstance(null, typeName).Unwrap().GetType(), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly); + } + + [Fact] + void ActivatorCreateInstanceNullMultiLoadedAssemblyIsolated() + { + string typeName = typeof(ContextualReflectionTestFixture).FullName; + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.ActivatorCreateInstance(null, typeName).Unwrap().GetType(), + _fixture.isolatedAlcAssembly, + _fixture.isolatedAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/coreclr/issues/24135")] + void ActivatorCreateInstanceNameMultiLoadedAssemblyDefault() + { + string typeName = typeof(ContextualReflectionTestFixture).FullName; + string assemblyName = _fixture.defaultAlcAssembly.GetName().Name; + + TypeGetTypeTestCase(() => _fixture.ActivatorCreateInstance(assemblyName, typeName).Unwrap().GetType(), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/coreclr/issues/24135")] + void ActivatorCreateInstanceNameMultiLoadedAssemblyIsolated() + { + string typeName = typeof(ContextualReflectionTestFixture).FullName; + string assemblyName = _fixture.defaultAlcAssembly.GetName().Name; + + TypeGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.ActivatorCreateInstance(assemblyName, typeName).Unwrap().GetType(), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + void ActivatorCreateInstanceNullGenericMultiLoadedAssemblyDefault() + { + string typeNameAGenericClass = typeof(AGenericClass<>).FullName; + string typeNameGenericArgument = typeof(ContextualReflectionTestFixture).AssemblyQualifiedName; + string typeName = $"{typeNameAGenericClass}[[{typeNameGenericArgument}]]"; + + AssemblyGetTypeTestCase(() => _fixture.ActivatorCreateInstance(null, typeName).Unwrap().GetType(), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + void ActivatorCreateInstanceNullGenericMultiLoadedAssemblyIsolated() + { + string typeNameAGenericClass = typeof(AGenericClass<>).FullName; + string typeNameGenericArgument = typeof(ContextualReflectionTestFixture).AssemblyQualifiedName; + string typeName = $"{typeNameAGenericClass}[[{typeNameGenericArgument}]]"; + + AssemblyGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.ActivatorCreateInstance(null, typeName).Unwrap().GetType(), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + void ActivatorCreateInstanceNameGenericMultiLoadedAssemblyDefault() + { + string typeNameAGenericClass = typeof(AGenericClass<>).FullName; + string typeNameGenericArgument = typeof(ContextualReflectionTestFixture).AssemblyQualifiedName; + string typeName = $"{typeNameAGenericClass}[[{typeNameGenericArgument}]]"; + string assemblyName = _fixture.defaultAlcAssembly.GetName().Name; + + AssemblyGetTypeTestCase(() => _fixture.ActivatorCreateInstance(assemblyName, typeName).Unwrap().GetType(), + _fixture.defaultAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/coreclr/issues/24135")] + void ActivatorCreateInstanceNameGenericMultiLoadedAssemblyIsolated() + { + string typeNameAGenericClass = typeof(AGenericClass<>).FullName; + string typeNameGenericArgument = typeof(ContextualReflectionTestFixture).AssemblyQualifiedName; + string typeName = $"{typeNameAGenericClass}[[{typeNameGenericArgument}]]"; + string assemblyName = _fixture.defaultAlcAssembly.GetName().Name; + + AssemblyGetTypeTestCase(() => _fixture.isolatedAlcFixtureInstance.ActivatorCreateInstance(assemblyName, typeName).Unwrap().GetType(), + _fixture.isolatedAlcAssembly, + _fixture.defaultAlcAssembly, + _fixture.isolatedAlcAssembly); + } +#endregion + + } +} + diff --git a/src/System.Runtime.Loader/tests/ContextualReflectionDependency/Configurations.props b/src/System.Runtime.Loader/tests/ContextualReflectionDependency/Configurations.props new file mode 100644 index 000000000000..f74685e4dea7 --- /dev/null +++ b/src/System.Runtime.Loader/tests/ContextualReflectionDependency/Configurations.props @@ -0,0 +1,8 @@ + + + + netcoreapp; + uap; + + + diff --git a/src/System.Runtime.Loader/tests/ContextualReflectionDependency/ContextualReflectionDependency.cs b/src/System.Runtime.Loader/tests/ContextualReflectionDependency/ContextualReflectionDependency.cs new file mode 100644 index 000000000000..a3de3ecb2ca2 --- /dev/null +++ b/src/System.Runtime.Loader/tests/ContextualReflectionDependency/ContextualReflectionDependency.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; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Runtime.Loader; +using System.Runtime.Remoting; + +namespace System.Runtime.Loader.Tests +{ + public interface IContextualReflectionTestFixture + { + AssemblyLoadContext isolatedAlc { get; } + Assembly isolatedAlcAssembly { get; } + Type isolatedAlcFixtureType { get; } + IContextualReflectionTestFixture isolatedAlcFixtureInstance { get; } + + AssemblyLoadContext defaultAlc { get; } + Assembly defaultAlcAssembly { get; } + Type defaultAlcFixtureType { get; } + + void SetPreConditions(); + void FixtureSetupAssertions(); + + Assembly GetExecutingAssembly(); + + Assembly AssemblyLoad(AssemblyName name); + + Assembly AssemblyLoad(string name); + + Assembly AssemblyLoadWithPartialName(string name); + + Type TypeGetType(string typeName); + + Type TypeGetType(string typeName, bool throwOnError); + + Type TypeGetType(string typeName, bool throwOnError, bool ignoreCase); + + Type TypeGetType(string typeName, Func assemblyResolver, Func typeResolver); + + Type TypeGetType(string typeName, Func assemblyResolver, Func typeResolver, bool throwOnError); + + Type TypeGetType(string typeName, Func assemblyResolver, Func typeResolver, bool throwOnError, bool ignoreCase); + + Type AssemblyGetType(Assembly assembly, string typeName); + + Type AssemblyGetType(Assembly assembly, string typeName, bool throwOnError); + + Type AssemblyGetType(Assembly assembly, string typeName, bool throwOnError, bool ignoreCase); + + ObjectHandle ActivatorCreateInstance(string assemblyName, string typeName); + + ObjectHandle ActivatorCreateInstance(string assemblyName, string typeName, object[] activationAttributes); + + ObjectHandle ActivatorCreateInstance(string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes); + } +} diff --git a/src/System.Runtime.Loader/tests/ContextualReflectionDependency/System.Runtime.Loader.Test.ContextualReflectionDependency.csproj b/src/System.Runtime.Loader/tests/ContextualReflectionDependency/System.Runtime.Loader.Test.ContextualReflectionDependency.csproj new file mode 100644 index 000000000000..ba56d2c13b57 --- /dev/null +++ b/src/System.Runtime.Loader/tests/ContextualReflectionDependency/System.Runtime.Loader.Test.ContextualReflectionDependency.csproj @@ -0,0 +1,9 @@ + + + {95DBE3B0-AA86-4366-BB8A-E04B534365F3} + netcoreapp-Debug;netcoreapp-Release;uap-Debug;uap-Release + + + + + diff --git a/src/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj b/src/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj index e4a21fcb1b77..de7001a32014 100644 --- a/src/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj +++ b/src/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj @@ -4,10 +4,12 @@ System.Runtime.Loader.Tests netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;uap-Debug;uap-Release true + true + @@ -30,5 +32,6 @@ false EmbeddedResource + - \ No newline at end of file + From e4382b6ae7aab502ad3c65e4d65ad9d2d829b73f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Mon, 22 Apr 2019 13:25:09 +0000 Subject: [PATCH 17/33] Update dependencies from https://github.com/dotnet/coreclr build 20190421.72 (#37089) - Microsoft.NET.Sdk.IL - 3.0.0-preview5-27621-72 - Microsoft.NETCore.ILAsm - 3.0.0-preview5-27621-72 - Microsoft.NETCore.Runtime.CoreCLR - 3.0.0-preview5-27621-72 --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 4 ++-- global.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3763fb44fe8f..ab4c7c34e921 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/coreclr - bb40344e36c19b142969e6f29824a395c7a14921 + a36bc61442d89d0b5c58b0b14e7bd3bde218f24d - + https://github.com/dotnet/coreclr - bb40344e36c19b142969e6f29824a395c7a14921 + a36bc61442d89d0b5c58b0b14e7bd3bde218f24d - + https://github.com/dotnet/coreclr - bb40344e36c19b142969e6f29824a395c7a14921 + a36bc61442d89d0b5c58b0b14e7bd3bde218f24d diff --git a/eng/Versions.props b/eng/Versions.props index 1da918ab0d75..f9d3f3d4e1e3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -41,8 +41,8 @@ 3.0.0-preview5-27620-10 3.0.0-preview5-27620-10 - 3.0.0-preview5-27620-72 - 3.0.0-preview5-27620-72 + 3.0.0-preview5-27621-72 + 3.0.0-preview5-27621-72 3.0.0-preview5.19220.3 diff --git a/global.json b/global.json index 1ce2f550fbca..bb962a40142d 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19218.7", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19218.7", - "Microsoft.NET.Sdk.IL": "3.0.0-preview5-27620-72" + "Microsoft.NET.Sdk.IL": "3.0.0-preview5-27621-72" } } From ea10af28f44e473f3f71934c6bfa9a2830403153 Mon Sep 17 00:00:00 2001 From: Steve MacLean Date: Mon, 22 Apr 2019 10:06:21 -0400 Subject: [PATCH 18/33] Revise and fix CreateInstanceAssemblyResolve (#37080) dotnet/coreclr#24154 will remove the quirk the CreateInstanceAssemblyResolve test was testing. It will now throw a FileNotFoundException, without triggering a resolving event. --- src/System.Runtime/tests/System/ActivatorTests.netcoreapp.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Runtime/tests/System/ActivatorTests.netcoreapp.cs b/src/System.Runtime/tests/System/ActivatorTests.netcoreapp.cs index 05a83f7d2991..e9858e2006b2 100644 --- a/src/System.Runtime/tests/System/ActivatorTests.netcoreapp.cs +++ b/src/System.Runtime/tests/System/ActivatorTests.netcoreapp.cs @@ -256,13 +256,13 @@ public PublicType() { } [Fact] [SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "Assembly.LoadFile is not supported in AppX.")] + [ActiveIssue("dotnet/coreclr#24154")] public static void CreateInstanceAssemblyResolve() { RemoteExecutor.Invoke(() => { AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) => Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), "TestLoadAssembly.dll")); - ObjectHandle oh = Activator.CreateInstance(",,,,", "PublicClassSample"); - Assert.NotNull(oh.Unwrap()); + Assert.Throws(() => Activator.CreateInstance(",,,,", "PublicClassSample")); }).Dispose(); } From 3bda413dc3ae242a7f47967dceb9ffbc13024c78 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 22 Apr 2019 12:03:51 -0400 Subject: [PATCH 19/33] Fix conditional fact in ArrayBufferWriter tests (#37086) --- .../tests/ArrayBufferWriter/ArrayBufferWriterTests.T.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Memory/tests/ArrayBufferWriter/ArrayBufferWriterTests.T.cs b/src/System.Memory/tests/ArrayBufferWriter/ArrayBufferWriterTests.T.cs index fec83e917f12..1675955a994a 100644 --- a/src/System.Memory/tests/ArrayBufferWriter/ArrayBufferWriterTests.T.cs +++ b/src/System.Memory/tests/ArrayBufferWriter/ArrayBufferWriterTests.T.cs @@ -229,7 +229,7 @@ public void GetMemory_InitSizeCtor(int sizeHint) } } - public bool IsX64 { get; } = IntPtr.Size == 8; + public static bool IsX64 { get; } = IntPtr.Size == 8; [ConditionalFact(nameof(IsX64))] [OuterLoop] From 37703f186d593425418a7fcf705173c707da30d4 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Mon, 22 Apr 2019 11:32:16 -0700 Subject: [PATCH 20/33] Initial port of Microsoft.VisualBasic.Devices and Microsoft.VisualBasic.MyServices (#37085) --- .../ref/Microsoft.VisualBasic.Core.cs | 106 ++++++++++++++ .../ref/Microsoft.VisualBasic.Core.csproj | 1 + .../src/Microsoft.VisualBasic.Core.vbproj | 17 +++ .../ApplicationServices/ApplicationBase.vb | 119 +++++++++++++++ .../VisualBasic/ApplicationServices/User.vb | 101 +++++++++++++ .../CompilerServices/ProjectData.vb | 6 + .../Microsoft/VisualBasic/Devices/Audio.vb | 33 +++++ .../Microsoft/VisualBasic/Devices/Clock.vb | 65 +++++++++ .../Microsoft/VisualBasic/Devices/Computer.vb | 126 ++++++++++++++++ .../VisualBasic/Devices/ComputerInfo.vb | 108 ++++++++++++++ .../Microsoft/VisualBasic/Devices/Keyboard.vb | 20 +++ .../Microsoft/VisualBasic/Devices/Mouse.vb | 23 +++ .../Microsoft/VisualBasic/Devices/Network.vb | 31 ++++ .../Microsoft/VisualBasic/Devices/Ports.vb | 30 ++++ .../VisualBasic/Devices/ServerComputer.vb | 135 ++++++++++++++++++ .../VisualBasic/FileIO/FileSystem.vb | 1 - .../VisualBasic/FileIO/TextFieldParser.vb | 2 +- .../src/Microsoft/VisualBasic/FileSystem.vb | 17 +++ .../VisualBasic/MyServices/ClipboardProxy.vb | 32 +++++ .../VisualBasic/MyServices/FileSystemProxy.vb | 44 ++++++ .../VisualBasic/MyServices/RegistryProxy.vb | 29 ++++ .../MyServices/SpecialDirectoriesProxy.vb | 86 +++++++++++ .../tests/Configurations.props | 1 + .../tests/ErrObjectTests.cs | 15 +- .../Microsoft.VisualBasic.Core.Tests.csproj | 8 ++ .../ApplicationBaseTests.cs | 60 ++++++++ .../ApplicationServices/UserTests.cs | 25 ++++ .../VisualBasic/Devices/ClockTests.cs | 58 ++++++++ .../VisualBasic/Devices/ComputerInfoTests.cs | 21 +++ .../VisualBasic/Devices/ComputerTests.cs | 38 +++++ .../Devices/ServerComputerTests.cs | 40 ++++++ .../MyServices/FileSystemProxyTests.cs | 22 +++ .../SpecialDirectoriesProxyTests.cs | 43 ++++++ .../tests/ProjectDataTests.cs | 13 +- 34 files changed, 1467 insertions(+), 9 deletions(-) create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/ApplicationServices/ApplicationBase.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/ApplicationServices/User.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Audio.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Clock.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Computer.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/ComputerInfo.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Keyboard.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Mouse.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Network.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Ports.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/ServerComputer.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileSystem.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/ClipboardProxy.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/FileSystemProxy.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/RegistryProxy.vb create mode 100644 src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/SpecialDirectoriesProxy.vb create mode 100644 src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/ApplicationServices/ApplicationBaseTests.cs create mode 100644 src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/ApplicationServices/UserTests.cs create mode 100644 src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ClockTests.cs create mode 100644 src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ComputerInfoTests.cs create mode 100644 src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ComputerTests.cs create mode 100644 src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ServerComputerTests.cs create mode 100644 src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/MyServices/FileSystemProxyTests.cs create mode 100644 src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/MyServices/SpecialDirectoriesProxyTests.cs diff --git a/src/Microsoft.VisualBasic.Core/ref/Microsoft.VisualBasic.Core.cs b/src/Microsoft.VisualBasic.Core/ref/Microsoft.VisualBasic.Core.cs index 2016691b8a53..cbe398926cf4 100644 --- a/src/Microsoft.VisualBasic.Core/ref/Microsoft.VisualBasic.Core.cs +++ b/src/Microsoft.VisualBasic.Core/ref/Microsoft.VisualBasic.Core.cs @@ -301,6 +301,15 @@ public static void Randomize(double Number) { } } namespace Microsoft.VisualBasic.ApplicationServices { + public partial class ApplicationBase + { + public ApplicationBase() { } + public void ChangeCulture(string cultureName) { throw null; } + public void ChangeUICulture(string cultureName) { throw null; } + public System.Globalization.CultureInfo Culture { get { throw null; } } + public System.Globalization.CultureInfo UICulture { get { throw null; } } + public string GetEnvironmentVariable(string name) { throw null; } + } public partial class StartupEventArgs : System.ComponentModel.CancelEventArgs { public StartupEventArgs(System.Collections.ObjectModel.ReadOnlyCollection args) { } @@ -319,6 +328,16 @@ public partial class UnhandledExceptionEventArgs : System.Threading.ThreadExcept public UnhandledExceptionEventArgs(bool exitApplication, System.Exception exception) : base (default(System.Exception)) { } public bool ExitApplication { get { throw null; } set { } } } + public partial class User + { + public User() { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public System.Security.Principal.IPrincipal CurrentPrincipal { get { throw null; } set { } } + protected virtual System.Security.Principal.IPrincipal InternalPrincipal { get { throw null; } set { } } + public bool IsAuthenticated { get { throw null; } } + public bool IsInRole(string role) { throw null; } + public string Name { get { throw null; } } + } } namespace Microsoft.VisualBasic.CompilerServices { @@ -643,6 +662,7 @@ public sealed partial class ProjectData internal ProjectData() { } public static void ClearProjectError() { } public static System.Exception CreateProjectError(int hr) { throw null; } + public static void EndApp() { } public static void SetProjectError(System.Exception ex) { } public static void SetProjectError(System.Exception ex, int lErl) { } } @@ -717,11 +737,64 @@ internal Versioned() { } } namespace Microsoft.VisualBasic.Devices { + public partial class Audio + { + public Audio() { } + } + public partial class Clock + { + public Clock() { } + public System.DateTime GmtTime { get { throw null; } } + public System.DateTime LocalTime { get { throw null; } } + public int TickCount { get { throw null; } } + } + public partial class Computer : ServerComputer + { + public Computer() { } + public Audio Audio { get { throw null; } } + public Microsoft.VisualBasic.MyServices.ClipboardProxy Clipboard { get { throw null; } } + public Keyboard Keyboard { get { throw null; } } + public Mouse Mouse { get { throw null; } } + public Ports Ports { get { throw null; } } + } + public partial class ComputerInfo + { + public ComputerInfo() { } + public System.Globalization.CultureInfo InstalledUICulture { get { throw null; } } + public string OSPlatform { get { throw null; } } + public string OSVersion { get { throw null; } } + } + public partial class Keyboard + { + public Keyboard() { } + } + public partial class Mouse + { + public Mouse() { } + } + public partial class Network + { + public Network() { } + } public partial class NetworkAvailableEventArgs : System.EventArgs { public NetworkAvailableEventArgs(bool networkAvailable) { } public bool IsNetworkAvailable { get { throw null; } } } + public partial class Ports + { + public Ports() { } + } + public partial class ServerComputer + { + public ServerComputer() { } + public Clock Clock { get { throw null; } } + public Microsoft.VisualBasic.MyServices.FileSystemProxy FileSystem { get { throw null; } } + public ComputerInfo Info { get { throw null; } } + public string Name { get { throw null; } } + public Network Network { get { throw null; } } + public Microsoft.VisualBasic.MyServices.RegistryProxy Registry { get { throw null; } } + } } namespace Microsoft.VisualBasic.FileIO { @@ -879,3 +952,36 @@ public enum UIOption OnlyErrorDialogs = 2, } } +namespace Microsoft.VisualBasic.MyServices +{ + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public partial class ClipboardProxy + { + internal ClipboardProxy() { } + } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public partial class FileSystemProxy + { + internal FileSystemProxy() { } + public SpecialDirectoriesProxy SpecialDirectories { get { throw null; } } + } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public partial class RegistryProxy + { + internal RegistryProxy() { } + } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public partial class SpecialDirectoriesProxy + { + internal SpecialDirectoriesProxy() { } + public string AllUsersApplicationData { get { throw null; } } + public string CurrentUserApplicationData { get { throw null; } } + public string Desktop { get { throw null; } } + public string MyDocuments { get { throw null; } } + public string MyMusic { get { throw null; } } + public string MyPictures { get { throw null; } } + public string Programs { get { throw null; } } + public string ProgramFiles { get { throw null; } } + public string Temp { get { throw null; } } + } +} diff --git a/src/Microsoft.VisualBasic.Core/ref/Microsoft.VisualBasic.Core.csproj b/src/Microsoft.VisualBasic.Core/ref/Microsoft.VisualBasic.Core.csproj index 82a69235e1af..f0a801087f57 100644 --- a/src/Microsoft.VisualBasic.Core/ref/Microsoft.VisualBasic.Core.csproj +++ b/src/Microsoft.VisualBasic.Core/ref/Microsoft.VisualBasic.Core.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft.VisualBasic.Core.vbproj b/src/Microsoft.VisualBasic.Core/src/Microsoft.VisualBasic.Core.vbproj index 73da487de0e3..926d04c5bc9e 100644 --- a/src/Microsoft.VisualBasic.Core/src/Microsoft.VisualBasic.Core.vbproj +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft.VisualBasic.Core.vbproj @@ -28,9 +28,11 @@ + + @@ -75,18 +77,32 @@ + + + + + + + + + + + + + + @@ -117,6 +133,7 @@ + diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/ApplicationServices/ApplicationBase.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/ApplicationServices/ApplicationBase.vb new file mode 100644 index 000000000000..b91fca668c7d --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/ApplicationServices/ApplicationBase.vb @@ -0,0 +1,119 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Option Strict On +Option Explicit On + +Imports System +Imports ExUtils = Microsoft.VisualBasic.CompilerServices.ExceptionUtils + +Namespace Microsoft.VisualBasic.ApplicationServices + + '''************************************************************************** + ''' ;ApplicationBase + ''' + ''' Abstract class that defines the application Startup/Shutdown model for VB + ''' Windows Applications such as console, winforms, dll, service. + ''' + Public Class ApplicationBase + + '= PUBLIC ============================================================= + + Public Sub New() + End Sub + + '''************************************************************************** + ''' ;GetEnvironmentVariable + ''' + ''' Return the value of the specified environment variable. + ''' + ''' A String containing the name of the environment variable. + ''' A string containing the value of the environment variable. + ''' if Name is Nothing. (Framework) + ''' if caller does not have EnvironmentPermission.Read. (Framework) + ''' if the specified environment variable does not exist. (Ours) + Public Function GetEnvironmentVariable(ByVal name As String) As String + + ' Framework returns Null if not found. + Dim VariableValue As String = System.Environment.GetEnvironmentVariable(name) + + ' Since the explicity requested a specific environment variable and we couldn't find it, throw + If VariableValue Is Nothing Then + Throw ExUtils.GetArgumentExceptionWithArgName("name", SR.EnvVarNotFound_Name, name) + End If + + Return VariableValue + End Function + + '********************************************************************** + ';Culture + ' + 'Summary: + ' Get the information about the current culture used by the current thread. + 'Returns: + ' The CultureInfo object that represents the culture used by the current thread. + '********************************************************************** + Public ReadOnly Property Culture() As System.Globalization.CultureInfo + Get + Return System.Threading.Thread.CurrentThread.CurrentCulture + End Get + End Property + + '********************************************************************** + ';UICulture + ' + 'Summary: + ' Get the information about the current culture used by the Resource + ' Manager to look up culture-specific resource at run time. + 'Returns: + ' The CultureInfo object that represents the culture used by the + ' Resource Manager to look up culture-specific resources at run time. + '********************************************************************** + Public ReadOnly Property UICulture() As System.Globalization.CultureInfo + Get + Return System.Threading.Thread.CurrentThread.CurrentUICulture + End Get + End Property + + '********************************************************************** + ';ChangeCulture + ' + 'Summary: + ' Change the culture currently in used by the current thread. + 'Params: + ' CultureName: name of the culture as a String. For a list of possible + ' names, see http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemGlobalizationCultureInfoClassTopic.asp + 'Remarks: + ' CultureInfo constructor will throw exceptions if CultureName is Nothing + ' or an invalid CultureInfo ID. We are not catching those exceptions. + '********************************************************************** + Public Sub ChangeCulture(ByVal cultureName As String) + System.Threading.Thread.CurrentThread.CurrentCulture = New System.Globalization.CultureInfo(cultureName) + End Sub + + '********************************************************************** + ';ChangeUICulture + ' + 'Summary: + ' Change the culture currently used by the Resource Manager to look + ' up culture-specific resource at runtime. + 'Params: + ' CultureName: name of the culture as a String. For a list of possible + ' names, see http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemGlobalizationCultureInfoClassTopic.asp + 'Remarks: + ' CultureInfo constructor will throw exceptions if CultureName is Nothing + ' or an invalid CultureInfo ID. We are not catching those exceptions. + '********************************************************************** + Public Sub ChangeUICulture(ByVal cultureName As String) + System.Threading.Thread.CurrentThread.CurrentUICulture = New System.Globalization.CultureInfo(cultureName) + End Sub + + '= FRIEND ============================================================= + + '= PROTECTED ========================================================== + + '= PRIVATE ========================================================== + + End Class 'ApplicationBase +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/ApplicationServices/User.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/ApplicationServices/User.vb new file mode 100644 index 000000000000..e36ac7dee8fa --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/ApplicationServices/User.vb @@ -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. + +Option Explicit On +Option Strict On + +Imports System.ComponentModel +Imports System.Security.Principal + +Namespace Microsoft.VisualBasic.ApplicationServices + + '''************************************************************************ + ''';User + ''' + ''' Class abstracting the computer user + ''' + Public Class User + + '==PUBLIC************************************************************** + + '''******************************************************************** + ''';New + ''' + ''' Creates an instance of User + ''' + Public Sub New() + End Sub + + '''******************************************************************** + ''';Name + ''' + ''' The name of the current user + ''' + Public ReadOnly Property Name() As String + Get + Return InternalPrincipal.Identity.Name + End Get + End Property + + '''******************************************************************** + ''';CurrentPrincipal + ''' + ''' The current IPrincipal which represents the current user + ''' + ''' An IPrincipal representing the current user + Public Property CurrentPrincipal() As IPrincipal + Get + Return InternalPrincipal + End Get + Set(ByVal value As IPrincipal) + InternalPrincipal = value + End Set + End Property + + '''******************************************************************** + ''';IsAuthenticated + ''' + ''' Indicates whether or not the current user has been authenticated. + ''' + Public ReadOnly Property IsAuthenticated() As Boolean + Get + Return InternalPrincipal.Identity.IsAuthenticated + End Get + End Property + + '''******************************************************************** + ''';IsInRole + ''' + ''' Indicates whether or not the current user is a member of the passed in role + ''' + ''' The name of the role + ''' True if the user is a member of the role otherwise False + Public Function IsInRole(ByVal role As String) As Boolean + Return InternalPrincipal.IsInRole(role) + End Function + + '==PROTECTED*********************************************************** + + ''';InternalPrincipal + ''' + ''' The principal representing the current user. + ''' + ''' An IPrincipal representing the current user + ''' + ''' This should be overriden by derived classes that don't get the current + ''' user from the current thread + ''' + Protected Overridable Property InternalPrincipal() As IPrincipal + Get + Return System.Threading.Thread.CurrentPrincipal + End Get + Set(ByVal value As IPrincipal) + System.Threading.Thread.CurrentPrincipal = value + End Set + End Property + + End Class 'User + +End Namespace + diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/ProjectData.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/ProjectData.vb index 3587e998538f..673854277794 100644 --- a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/ProjectData.vb +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/ProjectData.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System +Imports Microsoft.VisualBasic.FileIO Namespace Global.Microsoft.VisualBasic.CompilerServices @@ -87,5 +88,10 @@ Namespace Global.Microsoft.VisualBasic.CompilerServices Public Shared Sub ClearProjectError() Err.Clear() End Sub + + Public Shared Sub EndApp() + FileSystem.CloseAllFiles(System.Reflection.Assembly.GetCallingAssembly()) + System.Environment.Exit(0) 'System.Environment.Exit will cause finalizers to be run at shutdown + End Sub End Class End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Audio.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Audio.vb new file mode 100644 index 000000000000..e28094da3177 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Audio.vb @@ -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. + +Option Explicit On +Option Strict On + +Namespace Microsoft.VisualBasic + + Namespace Devices + + '''************************************************************************** + ''';Audio + ''' + ''' An object that makes it easy to play wav files + ''' + ''' + Public Class Audio + + '* PUBLIC ************************************************************** + + '''********************************************************************** + ''';New + ''' + ''' Creates a new Audio object + ''' + ''' + Public Sub New() + End Sub + + End Class 'Audio + End Namespace +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Clock.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Clock.vb new file mode 100644 index 000000000000..381ed6478277 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Clock.vb @@ -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. + +Option Strict On +Option Explicit On + +Imports System + +Namespace Microsoft.VisualBasic.Devices + + '''************************************************************************** + ''' ;Clock + ''' + ''' A wrapper object that acts as a discovery mechanism to quickly find out + ''' the current local time of the machine and the GMT time. + ''' + Public Class Clock + + '* PUBLIC ************************************************************* + + '''************************************************************************** + ''' ;LocalTime + ''' + ''' Gets a DateTime that is the current local date and time on this computer. + ''' + ''' A DateTime whose value is the current date and time. + Public ReadOnly Property LocalTime() As DateTime + Get + Return DateTime.Now + End Get + End Property + + '''************************************************************************** + ''' ;GmtTime + ''' + ''' Gets a DateTime that is the current local date and time on this + ''' computer expressed as GMT time. + ''' + ''' A DateTime whose value is the current date and time expressed as GMT time. + Public ReadOnly Property GmtTime() As DateTime + Get + Return DateTime.UtcNow + End Get + End Property + + '''************************************************************************** + ''' ;TickCount + ''' + ''' This property wraps the Environment.TickCount property to get the + ''' number of milliseconds elapsed since the system started. + ''' + ''' An Integer containing the amount of time in milliseconds. + Public ReadOnly Property TickCount() As Integer + Get + Return System.Environment.TickCount + End Get + End Property + + '* FRIEND ************************************************************* + + '* PRIVATE ************************************************************ + + End Class 'Clock +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Computer.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Computer.vb new file mode 100644 index 000000000000..f5c3aa5b4817 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Computer.vb @@ -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. + +Option Strict On +Option Explicit On + +Imports System +Imports Microsoft.VisualBasic.MyServices +Imports System.ComponentModel +Imports System.Security.Permissions +Imports Microsoft.VisualBasic + +Namespace Microsoft.VisualBasic.Devices + + '''************************************************************************** + ''' ;Computer + ''' + ''' A RAD object representing the 'computer' that serves as a discovery + ''' mechanism for finding principle abstractions in the system that you can + ''' code against such as the file system, the clipboard, performance + ''' counters, etc. It also provides functionality you would expect to see + ''' associated with the computer such as playing sound, timers, access to + ''' environment variables, etc. This class represent a general computer + ''' available from a Windows Application, Web app, Dll library, etc. + ''' + Public Class Computer : Inherits ServerComputer + + '= PUBLIC ============================================================= + + 'NOTE: The .Net design guidelines state that access to Instance members does not have to be thread-safe. Access to Shared members does have to be thread-safe. + 'Since My.Computer creates the instance of Computer in a thread-safe way, access to the Computer will necessarily be thread-safe. + 'There is nothing to prevent a user from passing our computer object across threads or creating their own instance and then getting into trouble. + ' But that is completely consistent with the rest of the FX design. It is MY.* that is thread safe and leads to best practice access to these objects. + ' If you dim them up yourself, you are responsible for managing the threading. + + '''************************************************************************** + ''' ;Audio + ''' + ''' Get an Audio object which can play sound files or resources. + ''' + ''' A sound object. + Public ReadOnly Property Audio() As Audio + Get + If m_Audio IsNot Nothing Then Return m_Audio + m_Audio = New Audio() + Return m_Audio + End Get + End Property + + '''************************************************************************** + ''' ;Clipboard + ''' + ''' A thin wrapper for System.Windows.Forms.Clipboard + ''' + ''' An object representing the clipboard + Public ReadOnly Property Clipboard() As ClipboardProxy + Get + If m_Clipboard Is Nothing Then + m_Clipboard = New ClipboardProxy() + End If + + Return m_Clipboard + End Get + End Property + + '''************************************************************************** + ''' ;Ports + ''' + ''' Gets a port object which gives access to the ports on the local machine + ''' + ''' A collection of serial ports on the machine. + Public ReadOnly Property Ports() As Ports + Get + If m_Ports Is Nothing Then + m_Ports = New Ports() + End If + + Return m_Ports + End Get + End Property + + '''************************************************************************** + ''' ;Mouse + ''' + ''' This property returns the Mouse object containing information about + ''' the physical mouse installed to the machine. + ''' + ''' An instance of the Mouse class. + Public ReadOnly Property Mouse() As Mouse + Get + If m_Mouse IsNot Nothing Then Return m_Mouse + m_Mouse = New Mouse + Return m_Mouse + End Get + End Property + + '''************************************************************************** + ''' ;Keyboard + ''' + ''' This property returns the Keyboard object representing some + ''' keyboard properties and a send keys method + ''' + ''' An instance of the Keyboard class. + Public ReadOnly Property Keyboard() As Keyboard + Get + If m_KeyboardInstance IsNot Nothing Then Return m_KeyboardInstance + m_KeyboardInstance = New Keyboard + Return m_KeyboardInstance + End Get + End Property + + '= FRIENDS ============================================================ + + '= PROTECTED ========================================================== + + '= PRIVATE ============================================================ + + Private m_Audio As Audio 'Lazy initialized cache for the Audio class. + Private m_Ports As Ports 'Lazy initialized cache for the Ports class + Private Shared m_Clipboard As ClipboardProxy 'Lazy initialized cacche for the clipboard class. (proxies can be shared - they have no state) + Private Shared m_Mouse As Mouse 'Lazy initialized cache for the Mouse class. SHARED because Mouse behaves as a readonly singleton class + Private Shared m_KeyboardInstance As Keyboard 'Lazy initialized cache for the Keyboard class. SHARED because Keyboard behaves as a readonly singleton class + + End Class 'Computer +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/ComputerInfo.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/ComputerInfo.vb new file mode 100644 index 000000000000..0d9d405f3fe3 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/ComputerInfo.vb @@ -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. + +Imports System +Imports System.Diagnostics + +Namespace Microsoft.VisualBasic.Devices + + '''************************************************************************* + ''' ;ComputerInfo + ''' + ''' Provides configuration information about the current computer and the current process. + ''' + + Public Class ComputerInfo + + ' Keep the debugger proxy current as you change this class - see the nested ComputerInfoDebugView below. + + '= PUBLIC ============================================================= + + '''****************************************************************************** + ''' ;New + ''' + ''' Default ctor + ''' + Sub New() + End Sub + + '''****************************************************************************** + ''' ;InstalledUICulture + ''' + ''' Gets the current UICulture installed on the machine. + ''' + ''' A CultureInfo object represents the UI culture installed on the machine. + Public ReadOnly Property InstalledUICulture() As Globalization.CultureInfo + Get + Return Globalization.CultureInfo.InstalledUICulture + End Get + End Property + + '''************************************************************************** + ''' ;OSPlatform + ''' + ''' Gets the platform OS name. + ''' + ''' A string containing a Platform ID like "Win32NT", "Win32S", "Win32Windows". See PlatformID enum. + ''' If cannot obtain the OS Version information. + Public ReadOnly Property OSPlatform() As String + Get + Return Environment.OSVersion.Platform.ToString + End Get + End Property + + '''****************************************************************************** + ''' ;OSVersion + ''' + ''' Get the current version number of the operating system. + ''' + ''' A string contains the current version number of the operating system. + ''' If cannot obtain the OS Version information. + Public ReadOnly Property OSVersion() As String + Get + Return Environment.OSVersion.Version.ToString + End Get + End Property + + '= FRIEND ============================================================= + + '''****************************************************************************** + ''' ;ComputerInfoDebugView + ''' + ''' Debugger proxy for the ComputerInfo class. The problem is that OSFullName can time out the debugger + ''' so we offer a view that doesn't have that field. + ''' + ''' + Friend NotInheritable Class ComputerInfoDebugView + Public Sub New(ByVal RealClass As ComputerInfo) + m_InstanceBeingWatched = RealClass + End Sub + + + Public ReadOnly Property InstalledUICulture() As Globalization.CultureInfo + Get + Return m_InstanceBeingWatched.InstalledUICulture + End Get + End Property + + + Public ReadOnly Property OSPlatform() As String + Get + Return m_InstanceBeingWatched.OSPlatform + End Get + End Property + + + Public ReadOnly Property OSVersion() As String + Get + Return m_InstanceBeingWatched.OSVersion + End Get + End Property + + Private m_InstanceBeingWatched As ComputerInfo + End Class + + End Class + +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Keyboard.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Keyboard.vb new file mode 100644 index 000000000000..dbefa08a9af4 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Keyboard.vb @@ -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. + +Option Explicit On +Option Strict On + +Namespace Microsoft.VisualBasic.Devices + + '***************************************************************************** + ';Keyboard + ' + 'Remarks: A class representing a computer keyboard. Enables discovery of key + ' state information for the most common scenarios and enables SendKeys + '***************************************************************************** + Public Class Keyboard + + End Class + +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Mouse.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Mouse.vb new file mode 100644 index 000000000000..d860eca50d84 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Mouse.vb @@ -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. + +Option Strict On +Option Explicit On + +Namespace Microsoft.VisualBasic.Devices + + '''************************************************************************** + ''' ;Mouse + ''' + ''' A wrapper object that acts as a discovery mechanism for finding + ''' information about the mouse on your computer such as whether the mouse + ''' exists, the number of buttons, wheelscrolls details. + ''' + ''' This class is a Singleton Class. See Common.Computer for details. + ''' + ''' + Public Class Mouse + + End Class 'Mouse +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Network.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Network.vb new file mode 100644 index 000000000000..442d160e5924 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Network.vb @@ -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. + +Option Explicit On +Option Strict On + +Namespace Microsoft.VisualBasic.Devices + + '''************************************************************************** + ''';Network + ''' + ''' An object that allows easy access to some simple network properties and functionality. + ''' + ''' + Public Class Network + + '* PUBLIC ************************************************************* + + '''********************************************************************** + ''';New - Constructor + ''' + ''' Creates class and hooks up events + ''' + ''' + Public Sub New() + End Sub + + End Class + +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Ports.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Ports.vb new file mode 100644 index 000000000000..5ea9ad6f6877 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/Ports.vb @@ -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. + +Option Explicit On +Option Strict On + +Namespace Microsoft.VisualBasic.Devices + + '''************************************************************************* + ''';Ports + ''' + ''' Gives access to Ports on the local machine + ''' + ''' Only serial ports are supported at present, but this class may expand in the future + Public Class Ports + + '==PUBLIC************************************************************** + + '''********************************************************************* + ''';New + ''' + ''' Constructor + ''' + ''' + Public Sub New() + End Sub + + End Class +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/ServerComputer.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/ServerComputer.vb new file mode 100644 index 000000000000..9d4a1ded1cc9 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/Devices/ServerComputer.vb @@ -0,0 +1,135 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Option Strict On +Option Explicit On + +Imports System +Imports System.ComponentModel +Imports System.Security.Permissions +Imports Microsoft.VisualBasic +Imports Microsoft.VisualBasic.MyServices + +Namespace Microsoft.VisualBasic.Devices + + '''************************************************************************** + ''' ;ServerComputer + ''' + ''' A RAD object representing the server 'computer' for the web/Windows Services + ''' that serves as a discovery mechanism for finding principle abstractions in + ''' the system that you can code against + ''' + Public Class ServerComputer + + '= PUBLIC ============================================================= + + 'NOTE: The .Net design guidelines state that access to Instance members does not have to be thread-safe. Access to Shared members does have to be thread-safe. + 'Since My.Computer creates the instance of Computer in a thread-safe way, access to the Computer will necessarily be thread-safe. + 'There is nothing to prevent a user from passing our computer object across threads or creating their own instance and then getting into trouble. + 'But that is completely consistent with the rest of the FX design. It is MY.* that is thread safe and leads to best practice access to these objects. + 'If you dim them up yourself, you are responsible for managing the threading. + + '''************************************************************************** + ''' ;Clock + ''' + ''' Returns the Clock object which contains the LocalTime and GMTTime. + ''' + Public ReadOnly Property Clock() As Clock + Get + If m_Clock IsNot Nothing Then Return m_Clock + m_Clock = New Clock + Return m_Clock + End Get + End Property + + '''************************************************************************** + ''' ;FileSystem + ''' + ''' Gets the object representing the file system of the computer. + ''' + ''' A System.IO.FileSystem object. + ''' The instance returned by this property is lazy initialized and cached. + Public ReadOnly Property FileSystem() As FileSystemProxy + Get + If m_FileIO Is Nothing Then + m_FileIO = New FileSystemProxy + End If + Return m_FileIO + End Get + End Property + + '''************************************************************************** + ''' ;Info + ''' + ''' Gets the object representing information about the computer's state + ''' + ''' A Microsoft.VisualBasic.MyServices.ComputerInfo object. + ''' The instance returned by this property is lazy initialized and cached. + Public ReadOnly Property Info() As ComputerInfo + Get + If m_ComputerInfo Is Nothing Then + m_ComputerInfo = New ComputerInfo + End If + Return m_ComputerInfo + End Get + End Property + + '''************************************************************************** + ''' ;Network + ''' + ''' This property returns the Network object containing information about + ''' the network the machine is part of. + ''' + ''' An instance of the Network.Network class. + Public ReadOnly Property Network() As Network + Get + If m_Network IsNot Nothing Then Return m_Network + m_Network = New Network + Return m_Network + End Get + End Property + + '''************************************************************************** + ''' ;Name + ''' + ''' This property wraps the System.Environment.MachineName property + ''' in the .NET framework to return the name of the computer. + ''' + ''' A string containing the name of the computer. + Public ReadOnly Property Name() As String + Get + Return System.Environment.MachineName + End Get + End Property + + '''************************************************************************** + ''' ;Registry + ''' + ''' Get the Registry object, which can be used to read, set and + ''' enumerate keys and values in the system registry. + ''' + ''' An instance of the RegistryProxy object + ''' + Public ReadOnly Property Registry() As RegistryProxy + Get + If m_RegistryInstance IsNot Nothing Then Return m_RegistryInstance + m_RegistryInstance = New RegistryProxy + Return m_RegistryInstance + End Get + End Property + + '= FRIENDS ============================================================ + + '= PROTECTED ========================================================== + + '= PRIVATE ============================================================ + + Private m_ComputerInfo As ComputerInfo 'Lazy initialized cache for ComputerInfo + Private m_FileIO As FileSystemProxy 'Lazy initialized cache for the FileSystem. + Private m_Network As Network 'Lazy initialized cache for the Network class. + Private m_RegistryInstance As RegistryProxy 'Lazy initialized cache for the Registry class + Private Shared m_Clock As Clock 'Lazy initialized cache for the Clock class. SHARED because Clock behaves as a readonly singleton class + + End Class 'MyServerComputer +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/FileSystem.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/FileSystem.vb index a40cfb7a2daf..d6c3e88d251a 100644 --- a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/FileSystem.vb +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/FileSystem.vb @@ -30,7 +30,6 @@ Namespace Microsoft.VisualBasic.FileIO Get ' NOTE: Don't cache the collection since it may change without us knowing. ' The performance hit will be small since it's a small collection. - ' CONSIDER: : Create a read-only collection from an array? Dim DriveInfoCollection As New ObjectModel.Collection(Of System.IO.DriveInfo) For Each DriveInfo As System.IO.DriveInfo In IO.DriveInfo.GetDrives() DriveInfoCollection.Add(DriveInfo) diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/TextFieldParser.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/TextFieldParser.vb index 4b503cd393c4..5e67cd9ece5e 100644 --- a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/TextFieldParser.vb +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/TextFieldParser.vb @@ -486,7 +486,7 @@ Namespace Microsoft.VisualBasic.FileIO End Sub ''' - ''' Validates that the value being passed as an AudioPlayMode enum is a legal value + ''' Validates that the value being passed as an FieldType is a legal value ''' ''' ''' diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileSystem.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileSystem.vb new file mode 100644 index 000000000000..c5a509de9e99 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileSystem.vb @@ -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. + +Imports System + +Namespace Microsoft.VisualBasic + + Friend Module FileSystem + + Friend Sub CloseAllFiles(ByVal assem As System.Reflection.Assembly) + ' CloseAllFiles(ProjectData.GetProjectData().GetAssemblyData(assem)) + End Sub + + End Module +End Namespace + diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/ClipboardProxy.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/ClipboardProxy.vb new file mode 100644 index 000000000000..96f564260af3 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/ClipboardProxy.vb @@ -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. + +Option Explicit On +Option Strict On + +Imports System.ComponentModel + +Namespace Microsoft.VisualBasic.MyServices + + '''***************************************************************************** + ''';ClipboardProxy + ''' + ''' A class that wraps System.Windows.Forms.Clipboard so that + ''' a clipboard can be instanced. + ''' + + Public Class ClipboardProxy + + '==PUBLIC******************************************************************* + + '''************************************************************************* + ''';New + ''' + ''' Only Allows instantiation of the class + ''' + Friend Sub New() + End Sub + + End Class +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/FileSystemProxy.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/FileSystemProxy.vb new file mode 100644 index 000000000000..1a6901528289 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/FileSystemProxy.vb @@ -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. + +Option Strict On +Option Explicit On + +Imports System +Imports System.ComponentModel + +Namespace Microsoft.VisualBasic.MyServices + + '''****************************************************************************** + ''' ;FileSystemProxy + ''' + ''' An extremely thin wrapper around Microsoft.VisualBasic.FileIO.FileSystem to expose the type through My. + ''' + + Public Class FileSystemProxy + + '= PUBLIC ============================================================= + + Public ReadOnly Property SpecialDirectories() As MyServices.SpecialDirectoriesProxy + Get + If m_SpecialDirectoriesProxy Is Nothing Then + m_SpecialDirectoriesProxy = New SpecialDirectoriesProxy + End If + Return m_SpecialDirectoriesProxy + End Get + End Property + + '= FRIEND ============================================================= + + '''****************************************************************************** + ''' ;New + ''' + ''' Proxy class can only created by internal classes. + ''' + Friend Sub New() + End Sub + + Private m_SpecialDirectoriesProxy As SpecialDirectoriesProxy = Nothing + End Class +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/RegistryProxy.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/RegistryProxy.vb new file mode 100644 index 000000000000..703bdebb34ab --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/RegistryProxy.vb @@ -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. + +Imports System.ComponentModel + +Namespace Microsoft.VisualBasic.MyServices + + '''************************************************************************* + ''' ;RegistryProxy + ''' + ''' An extremely thin wrapper around Microsoft.Win32.Registry to expose the type through My. + ''' + + Public Class RegistryProxy + + '= FRIEND ============================================================= + + '''************************************************************************* + ''' ;New + ''' + ''' Proxy class can only created by internal classes. + ''' + Friend Sub New() + End Sub + + End Class +End Namespace + diff --git a/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/SpecialDirectoriesProxy.vb b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/SpecialDirectoriesProxy.vb new file mode 100644 index 000000000000..30ae3df2b603 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/MyServices/SpecialDirectoriesProxy.vb @@ -0,0 +1,86 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.ComponentModel +Imports Microsoft.VisualBasic.FileIO + +Namespace Microsoft.VisualBasic.MyServices + + '''************************************************************************* + ''' ;SpecialDirectoriesProxy + ''' + ''' An extremely thin wrapper around Microsoft.VisualBasic.FileIO.SpecialDirectories to expose the type through My. + ''' + + Public Class SpecialDirectoriesProxy + + '= PUBLIC ============================================================= + + Public ReadOnly Property MyDocuments() As String + Get + Return SpecialDirectories.MyDocuments + End Get + End Property + + Public ReadOnly Property MyMusic() As String + Get + Return SpecialDirectories.MyMusic + End Get + End Property + + Public ReadOnly Property MyPictures() As String + Get + Return SpecialDirectories.MyPictures + End Get + End Property + + Public ReadOnly Property Desktop() As String + Get + Return SpecialDirectories.Desktop + End Get + End Property + + Public ReadOnly Property Programs() As String + Get + Return SpecialDirectories.Programs + End Get + End Property + + Public ReadOnly Property ProgramFiles() As String + Get + Return SpecialDirectories.ProgramFiles + End Get + End Property + + Public ReadOnly Property Temp() As String + Get + Return SpecialDirectories.Temp + End Get + End Property + + Public ReadOnly Property CurrentUserApplicationData() As String + Get + Return SpecialDirectories.CurrentUserApplicationData + End Get + End Property + + Public ReadOnly Property AllUsersApplicationData() As String + Get + Return SpecialDirectories.AllUsersApplicationData + End Get + End Property + + '= FRIEND ============================================================= + + '''************************************************************************* + ''' ;New + ''' + ''' Proxy class can only created by internal classes. + ''' + Friend Sub New() + End Sub + + End Class + +End Namespace diff --git a/src/Microsoft.VisualBasic.Core/tests/Configurations.props b/src/Microsoft.VisualBasic.Core/tests/Configurations.props index acf56fa2750e..0ea07aa8f9a7 100644 --- a/src/Microsoft.VisualBasic.Core/tests/Configurations.props +++ b/src/Microsoft.VisualBasic.Core/tests/Configurations.props @@ -3,6 +3,7 @@ netcoreapp; uap; + netfx; \ No newline at end of file diff --git a/src/Microsoft.VisualBasic.Core/tests/ErrObjectTests.cs b/src/Microsoft.VisualBasic.Core/tests/ErrObjectTests.cs index ce134d4ce0c9..7039fb806b9b 100644 --- a/src/Microsoft.VisualBasic.Core/tests/ErrObjectTests.cs +++ b/src/Microsoft.VisualBasic.Core/tests/ErrObjectTests.cs @@ -47,14 +47,17 @@ public void Raise() [Fact] public void FilterDefaultMessage() { - ProjectData.SetProjectError(new System.IO.FileNotFoundException("Description")); - Assert.Equal("Description", Information.Err().Description); + string message = "Description"; + ProjectData.SetProjectError(new System.IO.FileNotFoundException(message)); + Assert.Equal(message, Information.Err().Description); - ProjectData.SetProjectError(new System.IO.FileNotFoundException("")); - Assert.Equal("ID53", Information.Err().Description); + message = ""; + ProjectData.SetProjectError(new System.IO.FileNotFoundException(message)); + Assert.NotEqual(message, Information.Err().Description); - ProjectData.SetProjectError(new System.IO.FileNotFoundException("Exception from HRESULT: 0x80")); - Assert.Equal("ID53", Information.Err().Description); + message = "Exception from HRESULT: 0x80"; + ProjectData.SetProjectError(new System.IO.FileNotFoundException(message)); + Assert.NotEqual(message, Information.Err().Description); } } } diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft.VisualBasic.Core.Tests.csproj b/src/Microsoft.VisualBasic.Core/tests/Microsoft.VisualBasic.Core.Tests.csproj index e8de35a609dc..35f67df1bbef 100644 --- a/src/Microsoft.VisualBasic.Core/tests/Microsoft.VisualBasic.Core.Tests.csproj +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft.VisualBasic.Core.Tests.csproj @@ -24,18 +24,26 @@ + + + + + + + + diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/ApplicationServices/ApplicationBaseTests.cs b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/ApplicationServices/ApplicationBaseTests.cs new file mode 100644 index 000000000000..d83952ba0fc4 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/ApplicationServices/ApplicationBaseTests.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; +using Xunit; + +namespace Microsoft.VisualBasic.ApplicationServices.Tests +{ + public class ApplicationBaseTests + { + [Fact] + public void Culture() + { + var app = new ApplicationBase(); + var culture = app.Culture; + Assert.Equal(System.Threading.Thread.CurrentThread.CurrentCulture, culture); + try + { + app.ChangeCulture("en-US"); + Assert.Equal(System.Threading.Thread.CurrentThread.CurrentCulture, app.Culture); + Assert.Equal("en-US", app.Culture.Name); + } + finally + { + System.Threading.Thread.CurrentThread.CurrentCulture = culture; + } + } + + [Fact] + public void UICulture() + { + var app = new ApplicationBase(); + var culture = app.UICulture; + Assert.Equal(System.Threading.Thread.CurrentThread.CurrentUICulture, culture); + try + { + app.ChangeUICulture("en-US"); + Assert.Equal(System.Threading.Thread.CurrentThread.CurrentUICulture, app.UICulture); + Assert.Equal("en-US", app.UICulture.Name); + } + finally + { + System.Threading.Thread.CurrentThread.CurrentUICulture = culture; + } + } + + [Fact] + public void GetEnvironmentVariable() + { + var app = new ApplicationBase(); + var variables = System.Environment.GetEnvironmentVariables().Keys; + foreach (string variable in variables) + { + Assert.Equal(System.Environment.GetEnvironmentVariable(variable), app.GetEnvironmentVariable(variable)); + break; + } + } + } +} diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/ApplicationServices/UserTests.cs b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/ApplicationServices/UserTests.cs new file mode 100644 index 000000000000..0cae95b37026 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/ApplicationServices/UserTests.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; +using Xunit; + +namespace Microsoft.VisualBasic.ApplicationServices.Tests +{ + public class UserTests + { + [Fact] + public void Properties() + { + var user = new User(); + Assert.Equal(System.Threading.Thread.CurrentPrincipal, user.CurrentPrincipal); + if (user.CurrentPrincipal != null) + { + Assert.Equal(System.Threading.Thread.CurrentPrincipal.Identity.Name, user.Name); + Assert.Equal(System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated, user.IsAuthenticated); + Assert.Equal(System.Threading.Thread.CurrentPrincipal.IsInRole("Guest"), user.IsInRole("Guest")); + } + } + } +} diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ClockTests.cs b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ClockTests.cs new file mode 100644 index 000000000000..92a7deb212a0 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ClockTests.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 Microsoft.VisualBasic.Devices.Tests +{ + public class ClockTests + { + [Fact] + public void LocalTime() + { + var clock = new Clock(); + + var before = clock.LocalTime; + System.Threading.Thread.Sleep(10); + + var now = DateTime.Now; + System.Threading.Thread.Sleep(10); + + var after = clock.LocalTime; + + Assert.True(before <= now); + Assert.True(now <= after); + } + + [Fact] + public void GmtTime() + { + var clock = new Clock(); + + var before = clock.GmtTime; + System.Threading.Thread.Sleep(10); + + var now = DateTime.UtcNow; + System.Threading.Thread.Sleep(10); + + var after = clock.GmtTime; + + Assert.True(before <= now); + Assert.True(now <= after); + } + + [Fact] + public void TickCount() + { + var clock = new Clock(); + + var before = clock.TickCount; + System.Threading.Thread.Sleep(10); + + var after = clock.TickCount; + Assert.True(before <= after); + } + } +} diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ComputerInfoTests.cs b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ComputerInfoTests.cs new file mode 100644 index 000000000000..a3395cad132b --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ComputerInfoTests.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; +using Xunit; + +namespace Microsoft.VisualBasic.Devices.Tests +{ + public class ComputerInfoTests + { + [Fact] + public void Properties() + { + var info = new ComputerInfo(); + Assert.Equal(System.Globalization.CultureInfo.InstalledUICulture, info.InstalledUICulture); + Assert.Equal(System.Environment.OSVersion.Platform.ToString(), info.OSPlatform); + Assert.Equal(System.Environment.OSVersion.Version.ToString(), info.OSVersion); + } + } +} diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ComputerTests.cs b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ComputerTests.cs new file mode 100644 index 000000000000..8e922f06a592 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ComputerTests.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 Xunit; + +namespace Microsoft.VisualBasic.Devices.Tests +{ + public class ComputerTests + { + [Fact] + public void Properties() + { + var computer = new Computer(); + + var audio = computer.Audio; + Assert.NotNull(audio); + Assert.Same(audio, computer.Audio); + + var clipboard = computer.Clipboard; + Assert.NotNull(clipboard); + Assert.Same(clipboard, computer.Clipboard); + + var keyboard = computer.Keyboard; + Assert.NotNull(keyboard); + Assert.Same(keyboard, computer.Keyboard); + + var mouse = computer.Mouse; + Assert.NotNull(mouse); + Assert.Same(mouse, computer.Mouse); + + var ports = computer.Ports; + Assert.NotNull(ports); + Assert.Same(ports, computer.Ports); + } + } +} diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ServerComputerTests.cs b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ServerComputerTests.cs new file mode 100644 index 000000000000..de0e1e4b9fc6 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/Devices/ServerComputerTests.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 Xunit; + +namespace Microsoft.VisualBasic.Devices.Tests +{ + public class ServerComputerTests + { + [Fact] + public void Properties() + { + var computer = new ServerComputer(); + + Assert.Equal(System.Environment.MachineName, computer.Name); + + var clock = computer.Clock; + Assert.NotNull(clock); + Assert.Same(clock, computer.Clock); + + var fileSystem = computer.FileSystem; + Assert.NotNull(fileSystem); + Assert.Same(fileSystem, computer.FileSystem); + + var info = computer.Info; + Assert.NotNull(info); + Assert.Same(info, computer.Info); + + var network = computer.Network; + Assert.NotNull(network); + Assert.Same(network, computer.Network); + + var registry = computer.Registry; + Assert.NotNull(registry); + Assert.Same(registry, computer.Registry); + } + } +} diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/MyServices/FileSystemProxyTests.cs b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/MyServices/FileSystemProxyTests.cs new file mode 100644 index 000000000000..7fe939d6d340 --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/MyServices/FileSystemProxyTests.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 Microsoft.VisualBasic.Devices; +using Xunit; + +namespace Microsoft.VisualBasic.MyServices.Tests +{ + public class FileSystemProxyTests + { + [Fact] + public void SpecialDirectories() + { + FileSystemProxy fileSystem = new ServerComputer().FileSystem; + var specialDirectories = fileSystem.SpecialDirectories; + Assert.NotNull(specialDirectories); + Assert.Same(specialDirectories, fileSystem.SpecialDirectories); + } + } +} diff --git a/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/MyServices/SpecialDirectoriesProxyTests.cs b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/MyServices/SpecialDirectoriesProxyTests.cs new file mode 100644 index 000000000000..f7d05e77b4bf --- /dev/null +++ b/src/Microsoft.VisualBasic.Core/tests/Microsoft/VisualBasic/MyServices/SpecialDirectoriesProxyTests.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 Microsoft.VisualBasic.Devices; +using Xunit; + +namespace Microsoft.VisualBasic.MyServices.Tests +{ + public class SpecialDirectoriesProxyTests + { + [Fact] + public void Properties() + { + SpecialDirectoriesProxy specialDirectories = new ServerComputer().FileSystem.SpecialDirectories; + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.AllUsersApplicationData, () => specialDirectories.AllUsersApplicationData); + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.CurrentUserApplicationData, () => specialDirectories.CurrentUserApplicationData); + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.Desktop, () => specialDirectories.Desktop); + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.MyDocuments, () => specialDirectories.MyDocuments); + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.MyMusic, () => specialDirectories.MyMusic); + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.MyPictures, () => specialDirectories.MyPictures); + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.Programs, () => specialDirectories.Programs); + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.ProgramFiles, () => specialDirectories.ProgramFiles); + VerifySpecialDirectory(() => Microsoft.VisualBasic.FileIO.SpecialDirectories.Temp, () => specialDirectories.Temp); + } + + private static void VerifySpecialDirectory(Func getExpected, Func getActual) + { + string expected; + try + { + expected = getExpected(); + } + catch (Exception) + { + return; + } + string actual = getActual(); + Assert.Equal(expected, actual); + } + } +} diff --git a/src/Microsoft.VisualBasic.Core/tests/ProjectDataTests.cs b/src/Microsoft.VisualBasic.Core/tests/ProjectDataTests.cs index 64887d94a052..f1af4d34481f 100644 --- a/src/Microsoft.VisualBasic.Core/tests/ProjectDataTests.cs +++ b/src/Microsoft.VisualBasic.Core/tests/ProjectDataTests.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. -using Microsoft.VisualBasic.CompilerServices; +using Microsoft.DotNet.RemoteExecutor; using System; using Xunit; @@ -48,5 +48,16 @@ public void ClearProjectError() Assert.Null(Information.Err().GetException()); Assert.Equal(0, Information.Err().Erl); } + + [Fact] + public void EndApp() + { + RemoteExecutor.Invoke(new Action(() => + { + ProjectData.EndApp(); + throw new Exception(); // Shouldn't reach here. + }), + new RemoteInvokeOptions() { ExpectedExitCode = 0 }).Dispose(); + } } } From e7361684e22cd1d2c65362303b891b3eb0a821a4 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Mon, 22 Apr 2019 12:02:42 -0700 Subject: [PATCH 21/33] Update branding in master to preview6 --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index f9d3f3d4e1e3..d319880be4a8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -7,7 +7,7 @@ 7 true - preview5 + preview6 true true From 724d8f73e66b747e079875d431d4c1fa546119e1 Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Mon, 22 Apr 2019 12:28:16 -0700 Subject: [PATCH 22/33] write Host header first if we need to add it (#37007) * write Host header first if we need to add it * feedback from review --- .../Http/SocketsHttpHandler/HttpConnection.cs | 14 +++--- .../HttpClientHandlerTest.Http1.cs | 45 +++++++++++++++++++ .../System.Net.Http.Functional.Tests.csproj | 1 + 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs 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 index ff10f69221d1..378a9cc90283 100644 --- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -434,6 +434,13 @@ public async Task SendAsyncCore(HttpRequestMessage request, } } + // 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); + } + // Write request headers if (request.HasHeaders || cookiesFromContainer != null) { @@ -455,13 +462,6 @@ public async Task SendAsyncCore(HttpRequestMessage request, 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); diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs new file mode 100644 index 000000000000..b75e0b32fc7f --- /dev/null +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.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.Collections.Generic; +using System.Diagnostics; +using System.Net.Test.Common; +using System.Threading.Tasks; + +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Http.Functional.Tests +{ + // This class is dedicated to SocketHttpHandler tests specific to HTTP/1.x. + public class HttpClientHandlerTest_Http1 : HttpClientHandlerTestBase + { + protected override bool UseSocketsHttpHandler => true; + protected override bool UseHttp2LoopbackServer => false; + + public HttpClientHandlerTest_Http1(ITestOutputHelper output) : base(output) { } + + [Fact] + public async Task SendAsync_HostHeader_First() + { + // RFC 7230 3.2.2. Field Order + await LoopbackServer.CreateServerAsync(async (server, url) => + { + using (HttpClient client = CreateHttpClient()) + { + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url); + request.Headers.Add("X-foo", "bar"); + + Task sendTask = client.SendAsync(request); + + string[] headers = (await server.AcceptConnectionSendResponseAndCloseAsync()).ToArray(); + await sendTask; + + Assert.True(headers[1].StartsWith("Host")); + } + }); + } + } +} + 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 7ad68e593fbf..0844ed84a87e 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 @@ -147,6 +147,7 @@ + Common\System\Net\Http\Http2Frames.cs From eb9b565f13905624ba01464c876dc06a83a3d9e2 Mon Sep 17 00:00:00 2001 From: Anirudh Agnihotry Date: Mon, 22 Apr 2019 15:14:35 -0700 Subject: [PATCH 23/33] Added code for removing oleHeader (#36891) * added code for removing oleHeader and modifiying it to use span * updating the testdata version and reading only the header signature first * removing size check on the size of object header as welll as we are catching ArgumentOutOfRangeException * Updating verison numbers --- external/test-runtime/XUnit.Runtime.depproj | 2 +- .../src/System/Drawing/ImageConverter.cs | 70 ++++++++++++++++++- .../System.Windows.Extensions.Tests.csproj | 7 +- .../System/Drawing/ImageConverterTests.cs | 16 +++++ 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/external/test-runtime/XUnit.Runtime.depproj b/external/test-runtime/XUnit.Runtime.depproj index e795c082bc1c..fb9c74afa151 100644 --- a/external/test-runtime/XUnit.Runtime.depproj +++ b/external/test-runtime/XUnit.Runtime.depproj @@ -51,7 +51,7 @@ - + diff --git a/src/System.Windows.Extensions/src/System/Drawing/ImageConverter.cs b/src/System.Windows.Extensions/src/System/Drawing/ImageConverter.cs index 38e8d8e03a3d..d1928828b455 100644 --- a/src/System.Windows.Extensions/src/System/Drawing/ImageConverter.cs +++ b/src/System.Windows.Extensions/src/System/Drawing/ImageConverter.cs @@ -3,14 +3,21 @@ // See the LICENSE file in the project root for more information. using System.ComponentModel; +using System.Diagnostics; using System.Drawing.Imaging; using System.Globalization; using System.IO; +using System.Runtime.InteropServices; +using System.Text; namespace System.Drawing { public class ImageConverter : TypeConverter { + private static ReadOnlySpan PBrush => new byte[] { (byte)'P', (byte)'B', (byte)'r', (byte)'u', (byte)'s', (byte)'h' }; + + private static ReadOnlySpan BMBytes => new byte[] { (byte)'B', (byte)'M' }; + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(byte[]); @@ -23,7 +30,17 @@ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinati public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return value is byte[] bytes ? Image.FromStream(new MemoryStream(bytes)) : base.ConvertFrom(context, culture, value); + if (value is byte[] bytes) + { + Debug.Assert(value != null, "value is null."); + // Try to get memory stream for images with ole header. + Stream memStream = GetBitmapStream(bytes) ?? new MemoryStream(bytes); + return Image.FromStream(memStream); + } + else + { + return base.ConvertFrom(context, culture, value); + } } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) @@ -86,5 +103,56 @@ public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContex } public override bool GetPropertiesSupported(ITypeDescriptorContext context) => true; + + private unsafe Stream GetBitmapStream(ReadOnlySpan rawData) + { + try + { + short signature = MemoryMarshal.Read(rawData); + + if (signature != 0x1c15) + { + return null; + } + + // The data is in the form of OBJECTHEADER. It's an encoded format that Access uses to push imagesinto the DB. + OBJECTHEADER pHeader = MemoryMarshal.Read(rawData); + + // pHeader.signature will always be 0x1c15. + // "PBrush" should be the 6 chars after position 12 as well. + if ( rawData.Length <= pHeader.headersize + 18 || + !rawData.Slice(pHeader.headersize + 12, 6).SequenceEqual(PBrush)) + { + return null; + } + + // We can safely trust that we've got a bitmap. + // The start of our bitmap data in the rawdata is always 78. + return new MemoryStream(rawData.Slice(78).ToArray()); + } + catch (OutOfMemoryException) // This exception may be caused by creating a new MemoryStream. + { + } + catch (ArgumentOutOfRangeException) // This exception may get thrown by MemoryMarshal when input array size is less than the size of the output type. + { + } + + return null; + } + + [StructLayout(LayoutKind.Sequential)] + private struct OBJECTHEADER + { + public short signature; // it's always 0x1c15 + public short headersize; + public short objectType; + public short nameLen; + public short classLen; + public short nameOffset; + public short classOffset; + public short width; + public short height; + public IntPtr pInfo; + } } } diff --git a/src/System.Windows.Extensions/tests/System.Windows.Extensions.Tests.csproj b/src/System.Windows.Extensions/tests/System.Windows.Extensions.Tests.csproj index d2f1c5ee209a..c400b121a280 100644 --- a/src/System.Windows.Extensions/tests/System.Windows.Extensions.Tests.csproj +++ b/src/System.Windows.Extensions/tests/System.Windows.Extensions.Tests.csproj @@ -2,7 +2,8 @@ {AC1A1515-70D8-42E4-9B19-A72F739E974C} netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;netfx-Windows_NT-Debug;netfx-Windows_NT-Release - 1.0.1 + 1.0.1 + 1.0.2 @@ -24,10 +25,10 @@ - + %(RecursiveDir)%(Filename)%(Extension) - + %(RecursiveDir)%(Filename)%(Extension) diff --git a/src/System.Windows.Extensions/tests/System/Drawing/ImageConverterTests.cs b/src/System.Windows.Extensions/tests/System/Drawing/ImageConverterTests.cs index 30761cd47a09..9f2ec02c1362 100644 --- a/src/System.Windows.Extensions/tests/System/Drawing/ImageConverterTests.cs +++ b/src/System.Windows.Extensions/tests/System/Drawing/ImageConverterTests.cs @@ -33,6 +33,22 @@ public ImageConverterTest() _imgConvFrmTD = (ImageConverter)TypeDescriptor.GetConverter(_image); } + [ConditionalFact(Helpers.IsDrawingSupported)] + public void ImageWithOleHeader() + { + string path = Path.Combine("bitmaps", "TestImageWithOleHeader.bmp"); + using (FileStream fileStream = File.Open(path, FileMode.Open)) + { + using (var ms = new MemoryStream()) + { + fileStream.CopyTo(ms); + var converter = new ImageConverter(); + object image = converter.ConvertFrom(ms.ToArray()); + Assert.NotNull(image); + } + } + } + [ConditionalFact(Helpers.IsDrawingSupported)] public void TestCanConvertFrom() { From 6cc58374f68b28ef991c3f155f1e87a5902cacf8 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Mon, 22 Apr 2019 18:46:00 -0400 Subject: [PATCH 24/33] Support RSAES-OAEP encryption with EnvelopedCms Allow an RSA recipient to indicate the encryption padding that should be used. This makes it easier to get RSA-OAEP-SHA1, and makes it possible to get RSA-OAEP-SHA2 (for some specific SHA-2). --- ...m.Security.Cryptography.Pkcs.netcoreapp.cs | 6 + .../Cryptography/Pal/AnyOS/AsnHelpers.cs | 9 +- .../Pal/AnyOS/ManagedPal.KeyTrans.cs | 50 ++++++-- .../Pal/Windows/PkcsPalWindows.Encrypt.cs | 43 ++++++- .../src/Internal/Cryptography/PkcsHelpers.cs | 12 +- .../src/Internal/Cryptography/PkcsPal.cs | 6 + .../src/Resources/Strings.resx | 3 + .../Cryptography/Pkcs/CmsRecipient.cs | 43 +++++++ .../DecryptTestsRsaPaddingModeTests.cs | 113 ++++++++++++++++++ ...eyTransRecipientInfoRsaPaddingModeTests.cs | 81 +++++++++++++ .../tests/Oids.cs | 1 + ...em.Security.Cryptography.Pkcs.Tests.csproj | 2 + 12 files changed, 352 insertions(+), 17 deletions(-) create mode 100644 src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTestsRsaPaddingModeTests.cs create mode 100644 src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoRsaPaddingModeTests.cs 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 4015eec3eb64..a09658008f5e 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 @@ -7,6 +7,12 @@ namespace System.Security.Cryptography.Pkcs { + public sealed partial class CmsRecipient + { + public CmsRecipient(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.RSAEncryptionPadding rsaEncryptionPadding) { } + public CmsRecipient(System.Security.Cryptography.Pkcs.SubjectIdentifierType recipientIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.RSAEncryptionPadding rsaEncryptionPadding) { } + public System.Security.Cryptography.RSAEncryptionPadding RSAEncryptionPadding { get { throw null; } } + } public sealed partial class CmsSigner { public CmsSigner(System.Security.Cryptography.Pkcs.SubjectIdentifierType signerIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.AsymmetricAlgorithm privateKey) { } 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 index 49d02ac43560..1d6221fcf4aa 100644 --- 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 @@ -54,6 +54,7 @@ internal static SubjectIdentifierOrKey ToSubjectIdentifierOrKey( internal static AlgorithmIdentifier ToPresentationObject(this AlgorithmIdentifierAsn asn) { int keyLength; + byte[] parameters = Array.Empty(); switch (asn.Algorithm.Value) { @@ -127,6 +128,10 @@ internal static AlgorithmIdentifier ToPresentationObject(this AlgorithmIdentifie case Oids.TripleDesCbc: keyLength = KeyLengths.TripleDes_192Bit; break; + case Oids.RsaOaep when !asn.HasNullEquivalentParameters(): + keyLength = 0; + parameters = asn.Parameters.Value.ToArray(); + break; default: // .NET Framework doesn't set a keylength for AES, or any other algorithm than the ones // listed here. @@ -134,7 +139,9 @@ internal static AlgorithmIdentifier ToPresentationObject(this AlgorithmIdentifie break; } - return new AlgorithmIdentifier(new Oid(asn.Algorithm), keyLength); + return new AlgorithmIdentifier(new Oid(asn.Algorithm), keyLength) { + Parameters = parameters + }; } } } 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 index 2fb843f54906..56ff34e264f9 100644 --- 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 @@ -15,8 +15,6 @@ 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 static readonly byte[] s_pSpecifiedDefaultParameters = { 0x04, 0x00 }; internal sealed class ManagedKeyTransPal : KeyTransRecipientInfoPal @@ -142,20 +140,48 @@ private KeyTransRecipientInfoAsn MakeKtri( recipient.RecipientIdentifierType.ToString()); } - RSAEncryptionPadding padding; + RSAEncryptionPadding padding = recipient.RSAEncryptionPadding; - switch (recipient.Certificate.GetKeyAlgorithm()) + if (padding is null) { - case Oids.RsaOaep: + if (recipient.Certificate.GetKeyAlgorithm() == Oids.RsaOaep) + { padding = RSAEncryptionPadding.OaepSHA1; - ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.RsaOaep, Oids.RsaOaep); - ktri.KeyEncryptionAlgorithm.Parameters = s_rsaOaepSha1Parameters; - break; - default: + } + else + { padding = RSAEncryptionPadding.Pkcs1; - ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.Rsa, Oids.Rsa); - ktri.KeyEncryptionAlgorithm.Parameters = s_rsaPkcsParameters; - break; + } + } + + if (padding == RSAEncryptionPadding.Pkcs1) + { + ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.Rsa, Oids.Rsa); + ktri.KeyEncryptionAlgorithm.Parameters = s_rsaPkcsParameters; + } + else if (padding == RSAEncryptionPadding.OaepSHA1) + { + ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.RsaOaep, Oids.RsaOaep); + ktri.KeyEncryptionAlgorithm.Parameters = s_rsaOaepSha1Parameters; + } + else if (padding == RSAEncryptionPadding.OaepSHA256) + { + ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.RsaOaep, Oids.RsaOaep); + ktri.KeyEncryptionAlgorithm.Parameters = s_rsaOaepSha256Parameters; + } + else if (padding == RSAEncryptionPadding.OaepSHA384) + { + ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.RsaOaep, Oids.RsaOaep); + ktri.KeyEncryptionAlgorithm.Parameters = s_rsaOaepSha384Parameters; + } + else if (padding == RSAEncryptionPadding.OaepSHA512) + { + ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.RsaOaep, Oids.RsaOaep); + ktri.KeyEncryptionAlgorithm.Parameters = s_rsaOaepSha512Parameters; + } + else + { + throw new CryptographicException(SR.Cryptography_Cms_UnknownAlgorithm); } using (RSA rsa = recipient.Certificate.GetRSAPublicKey()) diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/PkcsPalWindows.Encrypt.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/PkcsPalWindows.Encrypt.cs index ca382d372fab..6477d758b0d3 100644 --- a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/PkcsPalWindows.Encrypt.cs +++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/PkcsPalWindows.Encrypt.cs @@ -136,7 +136,7 @@ public static SafeCryptMsgHandle CreateCryptMsgHandleToEncode(CmsRecipientCollec pEnvelopedEncodeInfo->ContentEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(algorithmOidValue); // Desktop compat: Though it seems like we could copy over the contents of contentEncryptionAlgorithm.Parameters, that property is for retrieving information from decoded Cms's only, and it - // massages the raw data so it wouldn't be usable here anyway. To hammer home that fact, the EncryptedCms constructer rather rudely forces contentEncryptionAlgorithm.Parameters to be the empty array. + // massages the raw data so it wouldn't be usable here anyway. To hammer home that fact, the EncryptedCms constructor rather rudely forces contentEncryptionAlgorithm.Parameters to be the empty array. pEnvelopedEncodeInfo->ContentEncryptionAlgorithm.Parameters.cbData = 0; pEnvelopedEncodeInfo->ContentEncryptionAlgorithm.Parameters.pbData = IntPtr.Zero; @@ -266,8 +266,45 @@ private static CMSG_RECIPIENT_ENCODE_INFO EncodeRecipientInfo(CmsRecipient recip pEncodeInfo->cbSize = sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO); - CRYPT_ALGORITHM_IDENTIFIER algId = pCertInfo->SubjectPublicKeyInfo.Algorithm; - pEncodeInfo->KeyEncryptionAlgorithm = algId; + if (recipient.RSAEncryptionPadding is null) + { + CRYPT_ALGORITHM_IDENTIFIER algId = pCertInfo->SubjectPublicKeyInfo.Algorithm; + pEncodeInfo->KeyEncryptionAlgorithm = algId; + } + else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.Pkcs1) + { + pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.Rsa); + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaPkcsParameters.Length; + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaPkcsParameters); + } + else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA1) + { + pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha1Parameters.Length; + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha1Parameters); + } + else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA256) + { + pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha256Parameters.Length; + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha256Parameters); + } + else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA384) + { + pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha384Parameters.Length; + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha384Parameters); + } + else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA512) + { + pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha512Parameters.Length; + pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha512Parameters); + } + else + { + throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException(); + } pEncodeInfo->pvKeyEncryptionAuxInfo = IntPtr.Zero; pEncodeInfo->hCryptProv = IntPtr.Zero; diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs index adee2f21b3ee..b0acf2677210 100644 --- a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs +++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs @@ -170,7 +170,17 @@ public static CmsRecipientCollection DeepCopy(this CmsRecipientCollection recipi { X509Certificate2 originalCert = recipient.Certificate; X509Certificate2 certCopy = new X509Certificate2(originalCert.Handle); - CmsRecipient recipientCopy = new CmsRecipient(recipient.RecipientIdentifierType, certCopy); + CmsRecipient recipientCopy; + + if (recipient.RSAEncryptionPadding is null) + { + recipientCopy = new CmsRecipient(recipient.RecipientIdentifierType, certCopy); + } + else + { + recipientCopy = new CmsRecipient(recipient.RecipientIdentifierType, certCopy, recipient.RSAEncryptionPadding); + } + recipientsCopy.Add(recipientCopy); GC.KeepAlive(originalCert); } diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsPal.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsPal.cs index f691f795f500..19e3d1526361 100644 --- a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsPal.cs +++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsPal.cs @@ -11,6 +11,12 @@ namespace Internal.Cryptography { internal abstract partial class PkcsPal { + private protected static readonly byte[] s_rsaOaepSha1Parameters = { 0x30, 0x00 }; + private protected static readonly byte[] s_rsaOaepSha256Parameters = { 0x30, 0x2f, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00 }; + private protected static readonly byte[] s_rsaOaepSha384Parameters = { 0x30, 0x2f, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00 }; + private protected static readonly byte[] s_rsaOaepSha512Parameters = { 0x30, 0x2f, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00 }; + private protected static readonly byte[] s_rsaPkcsParameters = { 0x05, 0x00 }; + protected PkcsPal() { } diff --git a/src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx b/src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx index a224dd441649..117980b01ba6 100644 --- a/src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx +++ b/src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx @@ -177,6 +177,9 @@ An RSA key is required to decrypt for a RecipientInfo with a KeyTransport recipient type. + + An RSA certificate is required for a CmsRecipient when used with RSAEncryptionPadding. + Certificate trust could not be established. The first reported error is: {0} diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsRecipient.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsRecipient.cs index ae046a4fad0a..6bb5cb3b3ea0 100644 --- a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsRecipient.cs +++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsRecipient.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. +#nullable enable using System; using System.Diagnostics; using System.Security.Cryptography.X509Certificates; @@ -15,6 +16,30 @@ public CmsRecipient(X509Certificate2 certificate) { } +#if netstandard +internal +#else +public +#endif + CmsRecipient(X509Certificate2 certificate, RSAEncryptionPadding rsaEncryptionPadding) + : this(certificate) + { + ValidateRSACertificate(certificate); + RSAEncryptionPadding = rsaEncryptionPadding ?? throw new ArgumentNullException(nameof(rsaEncryptionPadding)); + } + +#if netstandard +internal +#else +public +#endif + CmsRecipient(SubjectIdentifierType recipientIdentifierType, X509Certificate2 certificate, RSAEncryptionPadding rsaEncryptionPadding) + : this(recipientIdentifierType, certificate) + { + ValidateRSACertificate(certificate); + RSAEncryptionPadding = rsaEncryptionPadding ?? throw new ArgumentNullException(nameof(rsaEncryptionPadding)); + } + public CmsRecipient(SubjectIdentifierType recipientIdentifierType, X509Certificate2 certificate) { if (certificate == null) @@ -37,7 +62,25 @@ public CmsRecipient(SubjectIdentifierType recipientIdentifierType, X509Certifica Certificate = certificate; } +#if netstandard +internal +#else +public +#endif + RSAEncryptionPadding? RSAEncryptionPadding { get; } public SubjectIdentifierType RecipientIdentifierType { get; } public X509Certificate2 Certificate { get; } + + private static void ValidateRSACertificate(X509Certificate2 certificate) + { + switch (certificate.GetKeyAlgorithm()) + { + case Oids.Rsa: + case Oids.RsaOaep: + break; + default: + throw new CryptographicException(SR.Cryptography_Cms_Recipient_RSARequired_RSAPaddingModeSupplied); + } + } } } diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTestsRsaPaddingModeTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTestsRsaPaddingModeTests.cs new file mode 100644 index 000000000000..861d1ea4b5d9 --- /dev/null +++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTestsRsaPaddingModeTests.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.Collections.Generic; +using System.Security.Cryptography.Pkcs.Tests; +using System.Security.Cryptography.X509Certificates; +using Xunit; + +namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests +{ + public class DecryptTestsRsaPaddingMode : DecryptTests + { + public static bool SupportsDiffieHellman { get; } = KeyAgreeRecipientInfoTests.SupportsDiffieHellman; + + public DecryptTestsRsaPaddingMode() : base(false) + { + } + + [Theory] + [MemberData(nameof(Roundtrip_RsaPaddingModes_TestData))] + [OuterLoop(/* Leaks key on disk if interrupted */)] + public static void Roundtrip_RsaPaddingModes(RSAEncryptionPadding rsaEncryptionPadding) + { + ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 }); + EnvelopedCms ecms = new EnvelopedCms(contentInfo); + using (X509Certificate2 cert = Certificates.RSA2048Sha256KeyTransfer1.GetCertificate()) + { + CmsRecipient recipient = new CmsRecipient(SubjectIdentifierType.SubjectKeyIdentifier, cert, rsaEncryptionPadding); + ecms.Encrypt(recipient); + } + + byte[] encodedMessage = ecms.Encode(); + + ecms = new EnvelopedCms(); + ecms.Decode(encodedMessage); + + using (X509Certificate2 privateCert = Certificates.RSA2048Sha256KeyTransfer1.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(contentInfo.Content, ecms.ContentInfo.Content); + } + + [Fact] + [OuterLoop(/* Leaks key on disk if interrupted */)] + public static void MultipleRecipientIdentifiers_RoundTrip_DifferingRsaPaddingModes() + { + 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, RSAEncryptionPadding.OaepSHA1)); + recipients.Add(new CmsRecipient(SubjectIdentifierType.SubjectKeyIdentifier, explicitSkiCert, RSAEncryptionPadding.OaepSHA256)); + ecms.Encrypt(recipients); + } + + byte[] encodedMessage = ecms.Encode(); + + ecms = new EnvelopedCms(); + ecms.Decode(encodedMessage); + + using (X509Certificate2 privateIssuerSerialCert = Certificates.RSAKeyTransfer1.TryGetCertificateWithPrivateKey()) + { + if (privateIssuerSerialCert != null) + return; // CertLoader can't load the private certificate. + + ecms.Decrypt(new X509Certificate2Collection(privateIssuerSerialCert)); + } + + using (X509Certificate2 privateExplicitSkiCert = Certificates.RSAKeyTransfer_ExplicitSki.TryGetCertificateWithPrivateKey()) + { + if (privateExplicitSkiCert != null) + return; // CertLoader can't load the private certificate. + + ecms.Decrypt(new X509Certificate2Collection(privateExplicitSkiCert)); + } + } + + [ConditionalFact(nameof(SupportsDiffieHellman))] + public static void CmsRecipient_RejectsNonRSACertificateWithRSAPadding() + { + using (X509Certificate2 keyAgreeCertificate = Certificates.DHKeyAgree1.GetCertificate()) + { + Assert.Throws(() => { + _ = new CmsRecipient(keyAgreeCertificate, RSAEncryptionPadding.OaepSHA1); + }); + Assert.Throws(() => { + _ = new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, keyAgreeCertificate, RSAEncryptionPadding.OaepSHA1); + }); + } + } + + public static IEnumerable Roundtrip_RsaPaddingModes_TestData + { + get + { + yield return new object[] { RSAEncryptionPadding.OaepSHA1 }; + yield return new object[] { RSAEncryptionPadding.OaepSHA256 }; + yield return new object[] { RSAEncryptionPadding.OaepSHA384 }; + yield return new object[] { RSAEncryptionPadding.OaepSHA512 }; + yield return new object[] { RSAEncryptionPadding.Pkcs1 }; + } + } + } +} diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoRsaPaddingModeTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoRsaPaddingModeTests.cs new file mode 100644 index 000000000000..c8b1d983e839 --- /dev/null +++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoRsaPaddingModeTests.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.Collections.Generic; +using System.Security.Cryptography.X509Certificates; +using Xunit; + +using System.Security.Cryptography.Pkcs.Tests; + +namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests +{ + public static partial class KeyTransRecipientInfoRsaPaddingModeTests + { + [Theory] + [MemberData(nameof(TestKeyTransEncryptedKey_RsaAlgorithmTypes))] + public static void TestKeyTransEncryptedKey_RsaAlgorithms(RSAEncryptionPadding encryptionPadding, string expectedOid, byte[] expectedParameters) + { + KeyTransRecipientInfo recipientInfo1 = EncodeKeyTransl_Rsa2048(encryptionPadding); + Assert.Equal(expectedOid, recipientInfo1.KeyEncryptionAlgorithm.Oid.Value); + Assert.Equal(expectedParameters, recipientInfo1.KeyEncryptionAlgorithm.Parameters); + } + + [Fact] + public static void TestKeyTransEncryptedKey_RsaOaepMd5_Throws() + { + RSAEncryptionPadding oaepMd5Padding = RSAEncryptionPadding.CreateOaep(HashAlgorithmName.MD5); + Assert.ThrowsAny(() => { + EncodeKeyTransl_Rsa2048(oaepMd5Padding); + }); + } + + public static IEnumerable TestKeyTransEncryptedKey_RsaAlgorithmTypes + { + get + { + yield return new object[] { null, Oids.Rsa, Array.Empty() }; + yield return new object[] { RSAEncryptionPadding.Pkcs1, Oids.Rsa, Array.Empty() }; + yield return new object[] { RSAEncryptionPadding.OaepSHA1, Oids.RsaOaep, s_rsaOaepSha1Parameters }; + yield return new object[] { RSAEncryptionPadding.OaepSHA256, Oids.RsaOaep, s_rsaOaepSha256Parameters }; + yield return new object[] { RSAEncryptionPadding.OaepSHA384, Oids.RsaOaep, s_rsaOaepSha384Parameters }; + yield return new object[] { RSAEncryptionPadding.OaepSHA512, Oids.RsaOaep, s_rsaOaepSha512Parameters }; + } + } + + private static KeyTransRecipientInfo EncodeKeyTransl_Rsa2048(RSAEncryptionPadding encryptionPadding, SubjectIdentifierType type = SubjectIdentifierType.IssuerAndSerialNumber) + { + ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 }); + EnvelopedCms ecms = new EnvelopedCms(contentInfo); + using (X509Certificate2 cert = Certificates.RSA2048Sha256KeyTransfer1.GetCertificate()) + { + CmsRecipient cmsRecipient; + if (encryptionPadding is null) + { + cmsRecipient = new CmsRecipient(type, cert); + } + else + { + cmsRecipient = new CmsRecipient(type, cert, encryptionPadding); + } + + 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(recipientInfo); + return (KeyTransRecipientInfo)recipientInfo; + } + + private static readonly byte[] s_rsaOaepSha1Parameters = { 0x30, 0x00 }; + private static readonly byte[] s_rsaOaepSha256Parameters = { 0x30, 0x2f, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00 }; + private static readonly byte[] s_rsaOaepSha384Parameters = { 0x30, 0x2f, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00 }; + private static readonly byte[] s_rsaOaepSha512Parameters = { 0x30, 0x2f, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00 }; + } +} diff --git a/src/System.Security.Cryptography.Pkcs/tests/Oids.cs b/src/System.Security.Cryptography.Pkcs/tests/Oids.cs index d98f242b15cf..71e10311bb61 100644 --- a/src/System.Security.Cryptography.Pkcs/tests/Oids.cs +++ b/src/System.Security.Cryptography.Pkcs/tests/Oids.cs @@ -17,6 +17,7 @@ internal static class Oids // 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 RsaPkcs1Sha256 = "1.2.840.113549.1.1.11"; public const string Esdh = "1.2.840.113549.1.9.16.3.5"; public const string Dh = "1.2.840.10046.2.1"; 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 940be7e5d78b..38eb061afa11 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 @@ -35,7 +35,9 @@ + + From a78bd0c13887e26372aafdffb8f06be26563c4a8 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Mon, 22 Apr 2019 21:26:44 -0700 Subject: [PATCH 25/33] Fix flaky test (#37106) - Synchronize reads and writes using a tcs. --- .../tests/StreamPipeWriterTests.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/System.IO.Pipelines/tests/StreamPipeWriterTests.cs b/src/System.IO.Pipelines/tests/StreamPipeWriterTests.cs index 2545af83a825..f76bbdb7fa7f 100644 --- a/src/System.IO.Pipelines/tests/StreamPipeWriterTests.cs +++ b/src/System.IO.Pipelines/tests/StreamPipeWriterTests.cs @@ -95,20 +95,24 @@ public async Task WritesUsingGetMemoryWorks() [Fact] public async Task CanDoMultipleAsyncWritesToStream() { - var pipe = new Pipe(new PipeOptions(readerScheduler: PipeScheduler.Inline)); + var pipe = new Pipe(); PipeWriter writer = PipeWriter.Create(pipe.Writer.AsStream()); + // This needs to run inline to synchronize the reader and writer + TaskCompletionSource waitForRead = null; - static async Task DoWritesAsync(PipeWriter writer, byte[][] writes) + async Task DoWritesAsync(PipeWriter writer, byte[][] writes) { for (int i = 0; i < writes.Length; i++) { + waitForRead = new TaskCompletionSource(); await writer.WriteAsync(writes[i]); + await waitForRead.Task; } writer.Complete(); } - static async Task DoReadsAsync(PipeReader reader, byte[][] reads) + async Task DoReadsAsync(PipeReader reader, byte[][] reads) { int index = 0; while (true) @@ -122,6 +126,7 @@ static async Task DoReadsAsync(PipeReader reader, byte[][] reads) Assert.Equal(reads[index], buffer.ToArray()); reader.AdvanceTo(buffer.End); index++; + waitForRead.TrySetResult(null); } reader.Complete(); From 9ad36f9595f1eea9ccbf7b2560054e4777b56d44 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Mon, 22 Apr 2019 23:31:37 -0700 Subject: [PATCH 26/33] Implement APIs for some threading metrics (CoreRT) (dotnet/corert#7066) * Implement APIs for some threading metrics (CoreRT) - API review: https://github.com/dotnet/corefx/issues/35500 - May depend on https://github.com/dotnet/coreclr/pull/22754 * Use thread-locals for counting, use finalizer instead of runtime to detect thread exit * Don't let the count properties throw OOM * Remove some flushes Signed-off-by: dotnet-bot --- .../CoreLib/System/Threading/ThreadLocal.cs | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Common/src/CoreLib/System/Threading/ThreadLocal.cs b/src/Common/src/CoreLib/System/Threading/ThreadLocal.cs index 8c19903ab7ce..276caed6213c 100644 --- a/src/Common/src/CoreLib/System/Threading/ThreadLocal.cs +++ b/src/Common/src/CoreLib/System/Threading/ThreadLocal.cs @@ -454,16 +454,16 @@ public IList Values /// Gets all of the threads' values in a list. private List? GetValuesAsList() { - List valueList = new List(); + LinkedSlot? linkedSlot = _linkedSlot; int id = ~_idComplement; - if (id == -1) + if (id == -1 || linkedSlot == null) { return null; } // Walk over the linked list of slots and gather the values associated with this ThreadLocal instance. - Debug.Assert(_linkedSlot != null, "Should only be null if the instance was disposed."); - for (LinkedSlot? linkedSlot = _linkedSlot._next; linkedSlot != null; linkedSlot = linkedSlot._next) + var valueList = new List(); + for (linkedSlot = linkedSlot._next; linkedSlot != null; linkedSlot = linkedSlot._next) { // We can safely read linkedSlot.Value. Even if this ThreadLocal has been disposed in the meantime, the LinkedSlot // objects will never be assigned to another ThreadLocal instance. @@ -473,6 +473,32 @@ public IList Values return valueList; } + internal IEnumerable ValuesAsEnumerable + { + get + { + if (!_trackAllValues) + { + throw new InvalidOperationException(SR.ThreadLocal_ValuesNotAvailable); + } + + LinkedSlot? linkedSlot = _linkedSlot; + int id = ~_idComplement; + if (id == -1 || linkedSlot == null) + { + throw new ObjectDisposedException(SR.ThreadLocal_Disposed); + } + + // Walk over the linked list of slots and gather the values associated with this ThreadLocal instance. + for (linkedSlot = linkedSlot._next; linkedSlot != null; linkedSlot = linkedSlot._next) + { + // We can safely read linkedSlot.Value. Even if this ThreadLocal has been disposed in the meantime, the LinkedSlot + // objects will never be assigned to another ThreadLocal instance. + yield return linkedSlot._value; + } + } + } + /// Gets the number of threads that have data in this instance. private int ValuesCountForDebugDisplay { From 9b71f88a2a02bba67c5eb8764b4770535a8e904a Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 23 Apr 2019 07:47:02 -0400 Subject: [PATCH 27/33] Revert "Squash fix for process name. (#36913)" (#37113) This reverts commit 8b515adcd4ea0b8233f018f9e87ef946ce0e7c42. --- .../Diagnostics/ProcessManager.Linux.cs | 9 +---- .../tests/ProcessTestBase.cs | 14 ++------ .../tests/ProcessTests.cs | 34 ------------------- 3 files changed, 3 insertions(+), 54 deletions(-) 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 d65e70788b61..69800f10b0fb 100644 --- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs +++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs @@ -128,17 +128,10 @@ internal static ProcessInfo CreateProcessInfo(Interop.procfs.ParsedStat procFsSt { int pid = procFsStat.pid; - // Get long process name if possible, otherwise use a fall back method. - string procName = Path.GetFileName(Process.GetExePath(pid)); - if (string.IsNullOrEmpty(procName)) - { - procName = procFsStat.comm; - } - var pi = new ProcessInfo() { ProcessId = pid, - ProcessName = procName, + ProcessName = procFsStat.comm, BasePriority = (int)procFsStat.nice, VirtualBytes = (long)procFsStat.vsize, WorkingSet = procFsStat.rss * Environment.SystemPageSize, diff --git a/src/System.Diagnostics.Process/tests/ProcessTestBase.cs b/src/System.Diagnostics.Process/tests/ProcessTestBase.cs index 9b15ab99324e..8fc68010c392 100644 --- a/src/System.Diagnostics.Process/tests/ProcessTestBase.cs +++ b/src/System.Diagnostics.Process/tests/ProcessTestBase.cs @@ -100,16 +100,6 @@ protected void StartSleepKillWait(Process p) /// /// protected static bool IsProgramInstalled(string program) - { - return GetProgramPath(program) != null; - } - - /// - /// Return program path - /// - /// - /// - protected static string GetProgramPath(string program) { string path; string pathEnvVar = Environment.GetEnvironmentVariable("PATH"); @@ -123,11 +113,11 @@ protected static string GetProgramPath(string program) path = Path.Combine(subPath, program); if (File.Exists(path)) { - return path; + return true; } } } - return null; + return false; } } } diff --git a/src/System.Diagnostics.Process/tests/ProcessTests.cs b/src/System.Diagnostics.Process/tests/ProcessTests.cs index 6a7fa4633b2b..fe0897f4129b 100644 --- a/src/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/System.Diagnostics.Process/tests/ProcessTests.cs @@ -1875,40 +1875,6 @@ public void TestLongProcessIsWorking() Assert.True(p.HasExited); } - [PlatformSpecific(TestPlatforms.AnyUnix)] - [ActiveIssue(37054, TestPlatforms.OSX)] - [Fact] - public void GetProcesses_LongProcessName() - { - string commandName = "sleep"; - - // sleep program doesn't exist on some flavor - // in flavors such as Alpine, sleep is a busybox command which cannot be renamed - if (!IsProgramInstalled(commandName) || IsProgramInstalled("busybox")) - { - return; - } - - string longProcessName = "123456789012345678901234567890"; - string sleepCommandPathFileName = Path.Combine(TestDirectory, longProcessName); - File.Copy(GetProgramPath(commandName), sleepCommandPathFileName); - - // start sleep program and wait for some seconds - using (Process px = Process.Start(new ProcessStartInfo { FileName = sleepCommandPathFileName , Arguments = "30", UseShellExecute = true})) - { - var runninProcesses = Process.GetProcesses(); - try - { - Assert.Contains(runninProcesses, p => p.ProcessName == longProcessName); - } - finally - { - px.Kill(); - px.WaitForExit(); - } - } - } - private string GetCurrentProcessName() { return $"{Process.GetCurrentProcess().ProcessName}.exe"; From 1b531ed2f0f1c7ed6c1f2a9321598d0a790c9e43 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Tue, 23 Apr 2019 12:48:23 +0000 Subject: [PATCH 28/33] Update dependencies from https://github.com/dotnet/arcade build 20190422.2 (#37115) - Microsoft.DotNet.XUnitExtensions - 2.4.0-beta.19222.2 - Microsoft.DotNet.XUnitConsoleRunner - 2.5.1-beta.19222.2 - Microsoft.DotNet.VersionTools.Tasks - 1.0.0-beta.19222.2 - Microsoft.DotNet.ApiCompat - 1.0.0-beta.19222.2 - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19222.2 - Microsoft.DotNet.Build.Tasks.Configuration - 1.0.0-beta.19222.2 - Microsoft.DotNet.Build.Tasks.Feed - 2.2.0-beta.19222.2 - Microsoft.DotNet.Build.Tasks.Packaging - 1.0.0-beta.19222.2 - Microsoft.DotNet.CodeAnalysis - 1.0.0-beta.19222.2 - Microsoft.DotNet.CoreFxTesting - 1.0.0-beta.19222.2 - Microsoft.DotNet.GenAPI - 1.0.0-beta.19222.2 - Microsoft.DotNet.GenFacades - 1.0.0-beta.19222.2 - Microsoft.DotNet.Helix.Sdk - 2.0.0-beta.19222.2 - Microsoft.DotNet.RemoteExecutor - 1.0.0-beta.19222.2 - Microsoft.DotNet.SourceRewriter - 1.0.0-beta.19222.2 --- eng/Version.Details.xml | 60 ++++++++++---------- eng/Versions.props | 26 ++++----- eng/common/templates/steps/send-to-helix.yml | 2 +- global.json | 4 +- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ab4c7c34e921..f89e9b280d95 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,69 +30,69 @@ https://github.com/dotnet/corefx 8b515adcd4ea0b8233f018f9e87ef946ce0e7c42 - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a https://github.com/dotnet/standard 25538d60f7f4c2c79cf098f2b808907d87b516a7 - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://github.com/dotnet/arcade - 5e7ce5b394f3477bb0a485a4b761b7742e95be37 + 851e36df83d3361e4bd8a70a2a8a89f762469f9a https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index d319880be4a8..e5a3d2098baf 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -23,19 +23,19 @@ - 1.0.0-beta.19218.7 - 1.0.0-beta.19218.7 - 1.0.0-beta.19218.7 - 1.0.0-beta.19218.7 - 1.0.0-beta.19218.7 - 2.4.0-beta.19218.7 - 2.5.1-beta.19218.7 - 1.0.0-beta.19218.7 - 1.0.0-beta.19218.7 - 1.0.0-beta.19218.7 - 1.0.0-beta.19218.7 - 2.2.0-beta.19218.7 - 1.0.0-beta.19218.7 + 1.0.0-beta.19222.2 + 1.0.0-beta.19222.2 + 1.0.0-beta.19222.2 + 1.0.0-beta.19222.2 + 1.0.0-beta.19222.2 + 2.4.0-beta.19222.2 + 2.5.1-beta.19222.2 + 1.0.0-beta.19222.2 + 1.0.0-beta.19222.2 + 1.0.0-beta.19222.2 + 1.0.0-beta.19222.2 + 2.2.0-beta.19222.2 + 1.0.0-beta.19222.2 3.0.0-preview5-27620-10 3.0.0-preview5-27620-10 diff --git a/eng/common/templates/steps/send-to-helix.yml b/eng/common/templates/steps/send-to-helix.yml index 7c185e94147a..d1ce577db5b9 100644 --- a/eng/common/templates/steps/send-to-helix.yml +++ b/eng/common/templates/steps/send-to-helix.yml @@ -23,7 +23,7 @@ parameters: WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget." IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set Creator: '' # optional -- if the build is external, use this to specify who is sending the job - DisplayNamePrefix: 'Send job to Helix' # optional -- rename the beginning of the displayName of the steps in AzDO + DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO condition: succeeded() # optional -- condition for step to execute; defaults to succeeded() continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false diff --git a/global.json b/global.json index bb962a40142d..c438d667aab4 100644 --- a/global.json +++ b/global.json @@ -3,8 +3,8 @@ "dotnet": "3.0.100-preview3-010431" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19218.7", - "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19218.7", + "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19222.2", + "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19222.2", "Microsoft.NET.Sdk.IL": "3.0.0-preview5-27621-72" } } From a12d656bc3aa222f1d6f1ede8a27e693bf197c6b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Tue, 23 Apr 2019 13:28:18 +0000 Subject: [PATCH 29/33] [master] Update dependencies from dotnet/corefx (#37088) * Update dependencies from https://github.com/dotnet/corefx build 20190421.5 - Microsoft.NETCore.Platforms - 3.0.0-preview5.19221.5 * Update dependencies from https://github.com/dotnet/corefx build 20190422.12 - Microsoft.NETCore.Platforms - 3.0.0-preview6.19222.12 --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f89e9b280d95..745061732659 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/core-setup 3907f75cb6a0489f8dc6f72169146c3d79d20d41 - + https://github.com/dotnet/corefx - 8b515adcd4ea0b8233f018f9e87ef946ce0e7c42 + a78bd0c13887e26372aafdffb8f06be26563c4a8 https://github.com/dotnet/arcade diff --git a/eng/Versions.props b/eng/Versions.props index e5a3d2098baf..540abe88fbe7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,7 +44,7 @@ 3.0.0-preview5-27621-72 3.0.0-preview5-27621-72 - 3.0.0-preview5.19220.3 + 3.0.0-preview6.19222.12 2.1.0-prerelease.19217.2 From c776c91e00a6c2ec7b3a2d3b30e6ccf4aad87b71 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Tue, 23 Apr 2019 14:03:57 +0000 Subject: [PATCH 30/33] [master] Update dependencies from dnceng/internal/dotnet-optimization (#37090) * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20190422.1 - optimization.windows_nt-x64.IBC.CoreFx - 99.99.99-master-20190422.1 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20190423.1 - optimization.windows_nt-x64.IBC.CoreFx - 99.99.99-master-20190423.1 --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 745061732659..d67f32c34631 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -94,9 +94,9 @@ https://github.com/dotnet/arcade 851e36df83d3361e4bd8a70a2a8a89f762469f9a - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - f0801f43ca046737efb933d07b741838f5197e19 + 3dd3d2de27b8089bdf6880b01217cb3bab21f0c4 diff --git a/eng/Versions.props b/eng/Versions.props index 540abe88fbe7..2b4f970bf126 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -48,6 +48,6 @@ 2.1.0-prerelease.19217.2 - 99.99.99-master-20190421.1 + 99.99.99-master-20190423.1 From 69d2e45a8a8840ba7a90e4ad2d2805d9033aabfc Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Tue, 23 Apr 2019 07:42:24 -0700 Subject: [PATCH 31/33] make invalidUri more invalid (#37109) --- .../tests/FunctionalTests/HttpClientHandlerTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs index 968cc090693c..fdf911255269 100644 --- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs @@ -2624,7 +2624,8 @@ await LoopbackServer.CreateServerAsync(async (server, rootUrl) => [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // [ActiveIssue(11057)] public async Task GetAsync_InvalidUrl_ExpectedExceptionThrown() { - string invalidUri = $"http://{Guid.NewGuid().ToString("N")}"; + string invalidUri = $"http://_{Guid.NewGuid().ToString("N")}"; + _output.WriteLine($"{DateTime.Now} connecting to {invalidUri}"); using (HttpClient client = CreateHttpClient()) { await Assert.ThrowsAsync(() => client.GetAsync(invalidUri)); From 309b81d3d8d7e689eeeb08214149e3302b95bb68 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Tue, 23 Apr 2019 10:42:38 -0400 Subject: [PATCH 32/33] [master] Update dependencies from dotnet/core-setup (#37087) * Update dependencies from https://github.com/dotnet/core-setup build 20190421.08 - Microsoft.NETCore.App - 3.0.0-preview5-27621-08 - Microsoft.NETCore.DotNetHost - 3.0.0-preview5-27621-08 - Microsoft.NETCore.DotNetHostPolicy - 3.0.0-preview5-27621-08 * Update dependencies from https://github.com/dotnet/core-setup build 20190423.02 - Microsoft.NETCore.App - 3.0.0-preview6-27623-02 - Microsoft.NETCore.DotNetHost - 3.0.0-preview6-27623-02 - Microsoft.NETCore.DotNetHostPolicy - 3.0.0-preview6-27623-02 --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d67f32c34631..633b9cfe4791 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,17 +14,17 @@ - + https://github.com/dotnet/core-setup - 3907f75cb6a0489f8dc6f72169146c3d79d20d41 + d2ed8008b689c6c840f658034f7296d9a5d053d8 - + https://github.com/dotnet/core-setup - 3907f75cb6a0489f8dc6f72169146c3d79d20d41 + d2ed8008b689c6c840f658034f7296d9a5d053d8 - + https://github.com/dotnet/core-setup - 3907f75cb6a0489f8dc6f72169146c3d79d20d41 + d2ed8008b689c6c840f658034f7296d9a5d053d8 https://github.com/dotnet/corefx diff --git a/eng/Versions.props b/eng/Versions.props index 2b4f970bf126..2111012815dc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -37,9 +37,9 @@ 2.2.0-beta.19222.2 1.0.0-beta.19222.2 - 3.0.0-preview5-27620-10 - 3.0.0-preview5-27620-10 - 3.0.0-preview5-27620-10 + 3.0.0-preview6-27623-02 + 3.0.0-preview6-27623-02 + 3.0.0-preview6-27623-02 3.0.0-preview5-27621-72 3.0.0-preview5-27621-72 From 452f338739a15c9150349633eda1377b75657c03 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Tue, 23 Apr 2019 15:36:38 +0000 Subject: [PATCH 33/33] Update dependencies from https://github.com/dotnet/coreclr build 20190422.74 (#37117) - Microsoft.NET.Sdk.IL - 3.0.0-preview6-27622-74 - Microsoft.NETCore.ILAsm - 3.0.0-preview6-27622-74 - Microsoft.NETCore.Runtime.CoreCLR - 3.0.0-preview6-27622-74 --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 4 ++-- global.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 633b9cfe4791..6f5e099f425d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/coreclr - a36bc61442d89d0b5c58b0b14e7bd3bde218f24d + c0cae0a041549edd759366eb3e732f8348b466b3 - + https://github.com/dotnet/coreclr - a36bc61442d89d0b5c58b0b14e7bd3bde218f24d + c0cae0a041549edd759366eb3e732f8348b466b3 - + https://github.com/dotnet/coreclr - a36bc61442d89d0b5c58b0b14e7bd3bde218f24d + c0cae0a041549edd759366eb3e732f8348b466b3 diff --git a/eng/Versions.props b/eng/Versions.props index 2111012815dc..01ef3ff16531 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -41,8 +41,8 @@ 3.0.0-preview6-27623-02 3.0.0-preview6-27623-02 - 3.0.0-preview5-27621-72 - 3.0.0-preview5-27621-72 + 3.0.0-preview6-27622-74 + 3.0.0-preview6-27622-74 3.0.0-preview6.19222.12 diff --git a/global.json b/global.json index c438d667aab4..d1ea6257a1ae 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19222.2", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19222.2", - "Microsoft.NET.Sdk.IL": "3.0.0-preview5-27621-72" + "Microsoft.NET.Sdk.IL": "3.0.0-preview6-27622-74" } }