File: Commands\Test\MTP\Models.cs
Web Access
Project: ..\..\..\src\Cli\dotnet\dotnet.csproj (dotnet)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Diagnostics;
using Microsoft.DotNet.Cli.Commands.Run;
using Microsoft.DotNet.Cli.Commands.Run.LaunchSettings;
 
namespace Microsoft.DotNet.Cli.Commands.Test;
 
/// <summary>
/// Groups test modules that should NOT be run in parallel.
/// The whole group is still parallelizable with other groups, just that the inner modules are run sequentially.
/// This class serves only the purpose of disabling parallelizing of TFMs when user sets TestTfmsInParallel to false.
/// For a single TFM project, we will use the constructor with a single module. Meaning it will be parallelized.
/// For a multi TFM project:
/// - If parallelization is enabled, we will create multiple ParallelizableTestModuleGroupWithSequentialInnerModuless, each with a single module.
/// - If parallelization is not enabled, we will create a single ParallelizableTestModuleGroupWithSequentialInnerModules with all modules.
/// </summary>
internal sealed class ParallelizableTestModuleGroupWithSequentialInnerModules : IEnumerable<TestModule>
{
    public ParallelizableTestModuleGroupWithSequentialInnerModules(List<TestModule> modules)
    {
        Modules = modules;
    }
 
    public ParallelizableTestModuleGroupWithSequentialInnerModules(TestModule module)
    {
        // This constructor is used when there is only one module.
        Module = module;
    }
 
    public List<TestModule>? Modules { get; }
 
    public TestModule? Module { get; }
 
    public TestModule[] GetVSTestAndNotMTPModules()
    {
        if (Modules is not null)
        {
            return Modules.Where(module => !module.IsTestingPlatformApplication).ToArray();
        }
 
        Debug.Assert(Module is not null);
        if (!Module.IsTestingPlatformApplication)
        {
            return [Module];
        }
 
        return Array.Empty<TestModule>();
    }
 
    public Enumerator GetEnumerator()
        => new Enumerator(this);
 
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
    IEnumerator<TestModule> IEnumerable<TestModule>.GetEnumerator() => GetEnumerator();
 
    internal struct Enumerator : IEnumerator<TestModule>
    {
        private readonly ParallelizableTestModuleGroupWithSequentialInnerModules _group;
        private int _index = -1;
 
        public Enumerator(ParallelizableTestModuleGroupWithSequentialInnerModules group)
        {
            _group = group;
        }
 
        public TestModule Current
        {
            get
            {
                if (_index < 0)
                {
                    throw new InvalidOperationException();
                }
 
                if (_group.Modules is not null)
                {
                    return _group.Modules[_index];
                }
 
                if (_index != 0)
                {
                    throw new InvalidOperationException();
                }
 
                Debug.Assert(_group.Module is not null);
                return _group.Module;
            }
        }
 
        object IEnumerator.Current => Current;
 
        public void Dispose() { }
 
        public bool MoveNext()
        {
            _index++;
 
            if (_group.Modules is not null)
            {
                return _index < _group.Modules.Count;
            }
 
            return _index == 0;
        }
 
        public void Reset() => _index = -1;
    }
}
 
internal sealed record TestModule(RunProperties RunProperties, string? ProjectFullPath, string? TargetFramework, bool IsTestingPlatformApplication, ProjectLaunchSettingsModel? LaunchSettings, string TargetPath, string? DotnetRootArchVariableName);