Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<ItemGroup Label="Cli">
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionVersion)" />
<PackageVersion Include="Xamarin.Android.Tools.AndroidSdk" Version="$(XamarinAndroidToolsAndroidSdkVersion)" />
<PackageVersion Include="Xamarin.Apple.Tools.MaciOS" Version="$(XamarinAppleToolsMaciOSVersion)" />
</ItemGroup>

<!-- Platform extensions (pinned) -->
Expand Down
4 changes: 4 additions & 0 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
<Uri>https://github.com/dotnet/dotnet</Uri>
<Sha>73b3b5ac0e4a5658c7a0555b67d91a22ad39de4b</Sha>
</Dependency>
<Dependency Name="Xamarin.Apple.Tools.MaciOS" Version="1.0.0-preview.1.26201.1">
<Uri>https://github.com/dotnet/macios-devtools</Uri>
<Sha>14efcb9735fab369066fa3c99130d076aa0dfdc9</Sha>
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="10.0.0-beta.26168.104">
Expand Down
4 changes: 4 additions & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
<PropertyGroup Label="Android Tools">
<XamarinAndroidToolsAndroidSdkVersion>1.0.143-preview.8</XamarinAndroidToolsAndroidSdkVersion>
</PropertyGroup>
<!-- Apple platform tooling (managed via darc/maestro — see eng/Version.Details.xml) -->
<PropertyGroup Label="Apple Tools">
<XamarinAppleToolsMaciOSVersion>1.0.0-preview.1.26201.1</XamarinAppleToolsMaciOSVersion>
</PropertyGroup>
<PropertyGroup Label="Platform Extensions">
<PlatformMauiMacOSVersion>0.3.0</PlatformMauiMacOSVersion>
<PlatformMauiMacOSBlazorWebViewVersion>$(PlatformMauiMacOSVersion)</PlatformMauiMacOSBlazorWebViewVersion>
Expand Down
93 changes: 93 additions & 0 deletions src/Cli/Microsoft.Maui.Cli.UnitTests/DeviceManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,70 @@ public async Task GetAllDevicesAsync_ReturnsAndroidDevices()
Assert.Contains(devices, d => d.Platforms.Contains("android"));
}

[Fact]
public async Task GetAllDevicesAsync_ReturnsAppleSimulators()
{
// Arrange
var fakeApple = new FakeAppleProvider
{
Devices = new List<Device>
{
new Device
{
Id = "sim-udid-1234",
Name = "iPhone 15 Pro",
Platforms = new[] { "ios" },
Type = DeviceType.Simulator,
State = DeviceState.Booted,
IsEmulator = true,
IsRunning = true,
EmulatorId = "sim-udid-1234",
Version = "18.0"
}
}
};

var manager = new DeviceManager(appleProvider: fakeApple);

// Act
var devices = await manager.GetAllDevicesAsync();

// Assert
Assert.Single(devices);
Assert.Contains(devices, d => d.Platforms.Contains("ios"));
Assert.Equal(DeviceType.Simulator, devices[0].Type);
}

[Fact]
public async Task GetAllDevicesAsync_ReturnsBothAndroidAndApple()
{
// Arrange
var fakeAndroid = new FakeAndroidProvider
{
Devices = new List<Device>
{
new Device { Id = "emulator-5554", Name = "Pixel 6", Platforms = new[] { "android" }, Type = DeviceType.Emulator, State = DeviceState.Booted, IsEmulator = true, IsRunning = true }
}
};
var fakeApple = new FakeAppleProvider
{
Devices = new List<Device>
{
new Device { Id = "sim-udid", Name = "iPhone 15", Platforms = new[] { "ios" }, Type = DeviceType.Simulator, State = DeviceState.Booted, IsEmulator = true, IsRunning = true }
}
};

var manager = new DeviceManager(fakeAndroid, fakeApple);

// Act
var devices = await manager.GetAllDevicesAsync();

// Assert
Assert.Equal(2, devices.Count);
Assert.Contains(devices, d => d.Platforms.Contains("android"));
Assert.Contains(devices, d => d.Platforms.Contains("ios"));
}

[Fact]
public async Task GetDevicesByPlatformAsync_FiltersCorrectly()
{
Expand All @@ -55,6 +119,35 @@ public async Task GetDevicesByPlatformAsync_FiltersCorrectly()
Assert.All(androidOnly, d => Assert.Contains("android", d.Platforms));
}

[Fact]
public async Task GetDevicesByPlatformAsync_FiltersIosDevices()
{
// Arrange
var fakeAndroid = new FakeAndroidProvider
{
Devices = new List<Device>
{
new Device { Id = "emulator-5554", Name = "Pixel 6", Platforms = new[] { "android" }, Type = DeviceType.Emulator, State = DeviceState.Booted, IsEmulator = true, IsRunning = true }
}
};
var fakeApple = new FakeAppleProvider
{
Devices = new List<Device>
{
new Device { Id = "sim-udid", Name = "iPhone 15", Platforms = new[] { "ios" }, Type = DeviceType.Simulator, State = DeviceState.Booted, IsEmulator = true, IsRunning = true }
}
};

var manager = new DeviceManager(fakeAndroid, fakeApple);

// Act
var iosOnly = await manager.GetDevicesByPlatformAsync("ios");

// Assert
Assert.Single(iosOnly);
Assert.All(iosOnly, d => Assert.Contains("ios", d.Platforms));
}

[Fact]
public async Task GetDeviceByIdAsync_FindsCorrectDevice()
{
Expand Down
85 changes: 85 additions & 0 deletions src/Cli/Microsoft.Maui.Cli.UnitTests/DoctorServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,41 @@ public async Task RunAllChecksAsync_IncludesAndroidChecks_WhenProviderReturnsChe
Assert.Contains(report.Checks, c => c.Category == "android" && c.Name == "Android SDK");
}

[Fact]
public async Task RunAllChecksAsync_IncludesAppleChecks_WhenProviderReturnsChecks()
{
// Arrange
var fakeApple = new FakeAppleProvider
{
HealthChecks = new List<HealthCheck>
{
new HealthCheck
{
Category = "apple",
Name = "Xcode",
Status = CheckStatus.Ok,
Message = "Xcode 16.0"
},
new HealthCheck
{
Category = "apple",
Name = "Command Line Tools",
Status = CheckStatus.Ok,
Message = "CLT installed"
}
}
};

var service = new DoctorService(appleProvider: fakeApple);

// Act
var report = await service.RunAllChecksAsync();

// Assert
Assert.Contains(report.Checks, c => c.Category == "apple" && c.Name == "Xcode");
Assert.Contains(report.Checks, c => c.Category == "apple" && c.Name == "Command Line Tools");
}

[Fact]
public async Task RunAllChecksAsync_CalculatesCorrectSummary()
{
Expand Down Expand Up @@ -105,6 +140,27 @@ public async Task RunCategoryChecksAsync_SetsStatusBasedOnChecks()
Assert.NotEqual(HealthStatus.Unhealthy, report.Status);
}

[Fact]
public async Task RunCategoryChecksAsync_AppleCategory_ReturnsAppleChecks()
{
// Arrange
var fakeApple = new FakeAppleProvider
{
HealthChecks = new List<HealthCheck>
{
new HealthCheck { Category = "apple", Name = "Xcode", Status = CheckStatus.Ok, Message = "Xcode 16.0" }
}
};

var service = new DoctorService(appleProvider: fakeApple);

// Act
var report = await service.RunCategoryChecksAsync("apple");

// Assert
Assert.Contains(report.Checks, c => c.Category == "apple" && c.Name == "Xcode");
}

[Fact]
public async Task RunAllChecksAsync_IncludesAndroidChecks_WhenProviderReturnsAndroidOnly()
{
Expand All @@ -125,4 +181,33 @@ public async Task RunAllChecksAsync_IncludesAndroidChecks_WhenProviderReturnsAnd
// Assert - android checks should be present
Assert.Contains(report.Checks, c => c.Category == "android" && c.Name == "JDK");
}

[Fact]
public async Task RunAllChecksAsync_BothProviders_IncludesBothChecks()
{
// Arrange
var fakeAndroid = new FakeAndroidProvider
{
HealthChecks = new List<HealthCheck>
{
new HealthCheck { Category = "android", Name = "JDK", Status = CheckStatus.Ok }
}
};
var fakeApple = new FakeAppleProvider
{
HealthChecks = new List<HealthCheck>
{
new HealthCheck { Category = "apple", Name = "Xcode", Status = CheckStatus.Ok }
}
};

var service = new DoctorService(fakeAndroid, fakeApple);

// Act
var report = await service.RunAllChecksAsync();

// Assert
Assert.Contains(report.Checks, c => c.Category == "android");
Assert.Contains(report.Checks, c => c.Category == "apple");
}
}
96 changes: 96 additions & 0 deletions src/Cli/Microsoft.Maui.Cli.UnitTests/Fakes/FakeAppleProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Maui.Cli.Models;
using Microsoft.Maui.Cli.Providers.Apple;

namespace Microsoft.Maui.Cli.UnitTests.Fakes;

/// <summary>
/// Hand-written fake for <see cref="IAppleProvider"/> used in unit tests.
/// Set the public properties to control return values; inspect the tracking
/// lists to verify which methods were called and with what arguments.
/// </summary>
public class FakeAppleProvider : IAppleProvider
{
// --- Configurable return values ---

public List<XcodeInstallation> XcodeInstallations { get; set; } = new();
public XcodeInstallation? SelectedXcode { get; set; }
public CommandLineToolsStatus CltStatus { get; set; } = new();
public List<RuntimeInfo> Runtimes { get; set; } = new();
public List<SimulatorInfo> Simulators { get; set; } = new();
public List<HealthCheck> HealthChecks { get; set; } = new();
public List<Device> Devices { get; set; } = new();

public bool SelectXcodeResult { get; set; } = true;
public bool BootSimulatorResult { get; set; } = true;
public bool ShutdownSimulatorResult { get; set; } = true;
public bool DeleteSimulatorResult { get; set; } = true;
public string? CreateSimulatorResult { get; set; } = "new-udid";

// --- Call tracking ---

public List<string> SelectedXcodePaths { get; } = new();
public List<string> BootedSimulators { get; } = new();
public List<string> ShutdownSimulators { get; } = new();
public List<string> DeletedSimulators { get; } = new();
public List<(string Name, string DeviceType, string? Runtime)> CreatedSimulators { get; } = new();

// --- IAppleProvider implementation ---

public List<XcodeInstallation> GetXcodeInstallations() => XcodeInstallations;

public XcodeInstallation? GetSelectedXcode() => SelectedXcode;

public bool SelectXcode(string path)
{
SelectedXcodePaths.Add(path);
return SelectXcodeResult;
}

public CommandLineToolsStatus GetCommandLineToolsStatus() => CltStatus;

public List<RuntimeInfo> GetRuntimes(string? platform = null, bool availableOnly = false)
{
var result = Runtimes;
if (platform is not null)
result = result.Where(r => string.Equals(r.Platform, platform, StringComparison.OrdinalIgnoreCase)).ToList();
if (availableOnly)
result = result.Where(r => r.IsAvailable).ToList();
return result;
}

public List<SimulatorInfo> GetSimulators(bool availableOnly = false)
{
return availableOnly ? Simulators.Where(s => s.IsAvailable).ToList() : Simulators;
}

public bool BootSimulator(string udidOrName)
{
BootedSimulators.Add(udidOrName);
return BootSimulatorResult;
}

public bool ShutdownSimulator(string udidOrName)
{
ShutdownSimulators.Add(udidOrName);
return ShutdownSimulatorResult;
}

public bool DeleteSimulator(string udidOrName)
{
DeletedSimulators.Add(udidOrName);
return DeleteSimulatorResult;
}

public string? CreateSimulator(string name, string deviceTypeIdentifier, string? runtimeIdentifier = null)
{
CreatedSimulators.Add((name, deviceTypeIdentifier, runtimeIdentifier));
return CreateSimulatorResult;
}

public List<HealthCheck> CheckHealth() => HealthChecks;

public List<Device> GetDevices() => Devices;
}
Loading