diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx
index 4753042360fc..f427432c4561 100644
--- a/src/Cli/dotnet/Commands/CliCommandStrings.resx
+++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx
@@ -2434,6 +2434,18 @@ To display a value, specify the corresponding command-line option without provid
Manifest Version
+
+ Dependencies
+
+
+ Version
+
+
+ Recommended Version
+
+
+ optional
+
Couldn't find workload ID(s): {0}
diff --git a/src/Cli/dotnet/Commands/Workload/WorkloadInfoHelper.cs b/src/Cli/dotnet/Commands/Workload/WorkloadInfoHelper.cs
index abcd533aba52..be806d8656d4 100644
--- a/src/Cli/dotnet/Commands/Workload/WorkloadInfoHelper.cs
+++ b/src/Cli/dotnet/Commands/Workload/WorkloadInfoHelper.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.CommandLine;
+using System.Runtime.InteropServices;
+using System.Text.Json;
using Microsoft.Deployment.DotNet.Releases;
using Microsoft.DotNet.Cli.Commands.Workload.Install;
using Microsoft.DotNet.Cli.Commands.Workload.Install.WorkloadInstallRecords;
@@ -187,6 +189,9 @@ void WriteUpdateModeAndAnyError(string indent = "")
reporter.Write($"{separator}{CliCommandStrings.WorkloadInstallTypeColumn}:");
reporter.WriteLine($" {WorkloadInstallType.GetWorkloadInstallType(new SdkFeatureBand(Product.Version), dotnetPath).ToString(),align}"
);
+
+ PrintWorkloadDependencies(workloadManifest.ManifestPath, separator, reporter);
+
reporter.WriteLine("");
}
}
@@ -197,4 +202,189 @@ void WriteUpdateModeAndAnyError(string indent = "")
WriteUpdateModeAndAnyError();
}
}
+
+ private static void PrintWorkloadDependencies(string manifestPath, string separator, IReporter reporter)
+ {
+ var manifestDir = Path.GetDirectoryName(manifestPath);
+ if (manifestDir == null)
+ {
+ return;
+ }
+
+ var dependenciesPath = Path.Combine(manifestDir, "WorkloadDependencies.json");
+ if (!File.Exists(dependenciesPath))
+ {
+ return;
+ }
+
+ try
+ {
+ var json = File.ReadAllText(dependenciesPath);
+ using var doc = JsonDocument.Parse(json);
+
+ // The root object has workload manifest IDs as keys (e.g., "microsoft.net.sdk.android")
+ foreach (var manifestEntry in doc.RootElement.EnumerateObject())
+ {
+ // Each manifest entry contains dependency categories (e.g., "workload", "jdk", "androidsdk")
+ foreach (var category in manifestEntry.Value.EnumerateObject())
+ {
+ // Skip the "workload" category as it's metadata, not a dependency
+ if (category.Name.Equals("workload", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ reporter.WriteLine($"{separator}{CliCommandStrings.WorkloadDependenciesColumn} ({category.Name}):");
+ PrintDependencyCategory(category.Value, separator + " ", reporter);
+ }
+ }
+ }
+ catch (JsonException)
+ {
+ // Silently ignore malformed JSON
+ }
+ catch (IOException)
+ {
+ // Silently ignore file read errors
+ }
+ }
+
+ private static void PrintDependencyCategory(JsonElement category, string indent, IReporter reporter)
+ {
+ const int labelWidth = 21; // Align with "Recommended Version: "
+
+ foreach (var prop in category.EnumerateObject())
+ {
+ if (prop.Value.ValueKind == JsonValueKind.Array)
+ {
+ // Handle any array of items (packages, drivers, etc.)
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ PrintItemInfo(item, indent, labelWidth, reporter);
+ }
+ }
+ else
+ {
+ // Handle simple properties like "version", "recommendedVersion"
+ var value = GetJsonValueAsString(prop.Value);
+ if (!string.IsNullOrEmpty(value))
+ {
+ var displayName = GetLocalizedPropertyName(prop.Name);
+ var label = displayName + ":";
+ reporter.WriteLine($"{indent}{label.PadRight(labelWidth)}{value}");
+ }
+ }
+ }
+ }
+
+ private static string GetLocalizedPropertyName(string propertyName)
+ {
+ return propertyName.ToLowerInvariant() switch
+ {
+ "version" => CliCommandStrings.WorkloadDependencyVersion,
+ "recommendedversion" => CliCommandStrings.WorkloadDependencyRecommendedVersion,
+ _ => propertyName
+ };
+ }
+
+ private static void PrintItemInfo(JsonElement item, string indent, int labelWidth, IReporter reporter)
+ {
+ string? displayName = null;
+ string? id = null;
+ string? version = null;
+ string? recommendedVersion = null;
+ bool? optional = null;
+
+ foreach (var prop in item.EnumerateObject())
+ {
+ switch (prop.Name.ToLowerInvariant())
+ {
+ case "desc":
+ case "name":
+ displayName = GetJsonValueAsString(prop.Value);
+ break;
+ case "id":
+ id = GetJsonValueAsString(prop.Value);
+ break;
+ case "version":
+ version = GetJsonValueAsString(prop.Value);
+ break;
+ case "recommendedversion":
+ recommendedVersion = GetJsonValueAsString(prop.Value);
+ break;
+ case "optional":
+ optional = prop.Value.ValueKind == JsonValueKind.True ||
+ string.Equals(prop.Value.ToString(), bool.TrueString, StringComparison.OrdinalIgnoreCase);
+ break;
+ case "sdkpackage":
+ foreach (var sdkProp in prop.Value.EnumerateObject())
+ {
+ if (sdkProp.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
+ {
+ id = GetJsonValueAsString(sdkProp.Value);
+ }
+ else if (sdkProp.Name.Equals("recommendedVersion", StringComparison.OrdinalIgnoreCase))
+ {
+ recommendedVersion = GetJsonValueAsString(sdkProp.Value);
+ }
+ }
+ break;
+ }
+ }
+
+ if (!string.IsNullOrEmpty(displayName))
+ {
+ var optionalText = optional == true ? $" ({CliCommandStrings.WorkloadDependencyOptional})" : "";
+ reporter.WriteLine($"{indent}- {displayName}{optionalText}");
+ var detailIndent = indent + " ";
+ if (!string.IsNullOrEmpty(id))
+ {
+ reporter.WriteLine($"{detailIndent}{id}");
+ }
+ if (!string.IsNullOrEmpty(version))
+ {
+ var label = CliCommandStrings.WorkloadDependencyVersion + ":";
+ reporter.WriteLine($"{detailIndent}{label.PadRight(labelWidth)}{version}");
+ }
+ if (!string.IsNullOrEmpty(recommendedVersion))
+ {
+ var label = CliCommandStrings.WorkloadDependencyRecommendedVersion + ":";
+ reporter.WriteLine($"{detailIndent}{label.PadRight(labelWidth)}{recommendedVersion}");
+ }
+ }
+ }
+
+ private static string? GetJsonValueAsString(JsonElement element)
+ {
+ return element.ValueKind switch
+ {
+ JsonValueKind.String => element.GetString(),
+ JsonValueKind.Number => element.GetRawText(),
+ JsonValueKind.True => bool.TrueString,
+ JsonValueKind.False => bool.FalseString,
+ JsonValueKind.Object => GetPlatformSpecificId(element),
+ _ => null
+ };
+ }
+
+ private static string? GetPlatformSpecificId(JsonElement element)
+ {
+ // Handle platform-specific IDs like:
+ // "id": { "win-x64": "...", "mac-arm64": "...", ... }
+ var rid = RuntimeInformation.RuntimeIdentifier;
+
+ // Try exact match first
+ if (element.TryGetProperty(rid, out var exactMatch))
+ {
+ return GetJsonValueAsString(exactMatch);
+ }
+
+ // Fall back to first available
+ foreach (var prop in element.EnumerateObject())
+ {
+ return $"{GetJsonValueAsString(prop.Value)} ({prop.Name})";
+ }
+
+ return null;
+ }
}
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
index 293774c36807..9d307c71eb01 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
@@ -3735,6 +3735,26 @@ Pokud chcete zobrazit hodnotu, zadejte odpovídající volbu příkazového řá
Spravujte volitelné úlohy.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Spuštěním serverového procesu se zvýšenými oprávněními umožněte používat instalace založené na instalační službě MSI.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
index bf4889f2658d..ca1b8ac0cca3 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
@@ -3735,6 +3735,26 @@ Um einen Wert anzuzeigen, geben Sie die entsprechende Befehlszeilenoption an, oh
Verwalten Sie optionale Workloads.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Starten Sie den Serverprozess mit erhöhten Rechten, um MSI-basierte Installationen zu unterstützen.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
index 529999c31c77..8a15493c8cf1 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
@@ -3735,6 +3735,26 @@ Para mostrar un valor, especifique la opción de línea de comandos correspondie
Administrar cargas de trabajo opcionales.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Inicie el proceso de servidor elevado para facilitar las instalaciones basadas en MSI.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
index d70736f22461..507f65b1f43b 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
@@ -3735,6 +3735,26 @@ Pour afficher une valeur, spécifiez l’option de ligne de commande corresponda
Gérez les charges de travail facultatives.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Démarrez le processus du serveur avec élévation de privilèges pour faciliter les installations basées sur MSI.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
index 3b51ca4b1030..f3dba250ef74 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
@@ -3735,6 +3735,26 @@ Per visualizzare un valore, specifica l'opzione della riga di comando corrispond
Gestire i carichi di lavoro facoltativi.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Avviare il processo server con privilegi elevati per semplificare le installazioni basate su MSI.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
index c836504745c1..609770244dcb 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
@@ -3735,6 +3735,26 @@ To display a value, specify the corresponding command-line option without provid
オプションのワークロードを管理します。
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
昇格された特権のサーバー プロセスを開始して、MSI ベースのインストールを促進します。
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
index c33addce7195..e98ef2c0b550 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
@@ -3735,6 +3735,26 @@ To display a value, specify the corresponding command-line option without provid
선택적 워크로드를 관리합니다.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
MSI 기반 설치를 용이하게 하도록 관리자 권한 서버 프로세스를 시작합니다.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
index f89492285068..d5b35d74e90a 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
@@ -3735,6 +3735,26 @@ Aby wyświetlić wartość, należy podać odpowiednią opcję wiersza poleceń
Zarządzaj opcjonalnymi obciążeniami.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Rozpocznij proces podwyższonego poziomu serwera, aby ułatwić instalacje oparte na funkcjach MSI.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
index 81287d03948f..6730abf4f79f 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
@@ -3735,6 +3735,26 @@ Para exibir um valor, especifique a opção de linha de comando correspondente s
Gerenciar as cargas de trabalho opcionais.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Inicie o processo de servidor com privilégios elevados para facilitar instalações baseadas em MSI.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
index 52e2408c6370..862b4f109f58 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
@@ -3736,6 +3736,26 @@ To display a value, specify the corresponding command-line option without provid
Управление необязательными рабочими нагрузками.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Запустите серверный процесс с повышенными правами для упрощения установки на основе MSI.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
index 0bdf46014f3c..5ae7aa425bce 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
@@ -3735,6 +3735,26 @@ Bir değeri görüntülemek için, bir değer sağlamadan ilgili komut satırı
İsteğe bağlı iş yüklerini yönetin.
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
Windows Installer tabanlı yüklemeleri kolaylaştırmak için yükseltilmiş sunucu işlemini başlatın.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
index 196eb2de4133..0b014d641687 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
@@ -3735,6 +3735,26 @@ To display a value, specify the corresponding command-line option without provid
管理可选工作负荷。
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
启动提升的服务器进程以方便基于 MSI 的安装。
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
index a11d81925055..9fee5cbeb133 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
@@ -3735,6 +3735,26 @@ To display a value, specify the corresponding command-line option without provid
管理選擇性工作負載。
+
+ Dependencies
+ Dependencies
+
+
+
+ optional
+ optional
+
+
+
+ Recommended Version
+ Recommended Version
+
+
+
+ Version
+ Version
+
+
Start the elevated server process to facilitate MSI based installations.
啟動提升權限的伺服器處理序,以輔助 MSI 型安裝。
diff --git a/test/TestAssets/TestProjects/SampleManifest/WorkloadDependencies.json b/test/TestAssets/TestProjects/SampleManifest/WorkloadDependencies.json
new file mode 100644
index 000000000000..85fa56e8fca8
--- /dev/null
+++ b/test/TestAssets/TestProjects/SampleManifest/WorkloadDependencies.json
@@ -0,0 +1,77 @@
+{
+ "xamarin-android": {
+ "workload": {
+ "description": "This should be skipped"
+ },
+ "jdk": {
+ "version": "[11.0,18.0)",
+ "recommendedVersion": "11.0.12"
+ },
+ "androidsdk": {
+ "packages": [
+ {
+ "desc": "Android SDK Build-Tools 30",
+ "id": "build-tools;30.0.3"
+ },
+ {
+ "desc": "Android SDK Platform-Tools",
+ "sdkPackage": {
+ "id": "platform-tools",
+ "recommendedVersion": "31.0.3"
+ }
+ },
+ {
+ "desc": "Android Emulator",
+ "id": "emulator",
+ "optional": true,
+ "recommendedVersion": "31.2.10"
+ },
+ {
+ "desc": "Not Optional Item",
+ "id": "not-optional",
+ "optional": false
+ },
+ {
+ "desc": "Google APIs System Image",
+ "sdkPackage": {
+ "id": {
+ "win-x64": "system-images;android-35;google_apis;x86_64",
+ "win-arm64": "system-images;android-35;google_apis;x86_64",
+ "osx-x64": "system-images;android-35;google_apis;x86_64",
+ "osx-arm64": "system-images;android-35;google_apis;arm64-v8a",
+ "linux-x64": "system-images;android-35;google_apis;x86_64",
+ "linux-arm64": "system-images;android-35;google_apis;arm64-v8a"
+ }
+ },
+ "optional": true
+ }
+ ]
+ },
+ "appium": {
+ "version": "[2.17.1,)",
+ "recommendedVersion": "2.17.1",
+ "drivers": [
+ {
+ "name": "windows",
+ "version": "[3.1.1,)",
+ "recommendedVersion": "3.1.1"
+ },
+ {
+ "name": "xcuitest",
+ "version": "[7.32.0,)",
+ "recommendedVersion": "7.32.0"
+ },
+ {
+ "name": "mac2",
+ "version": "[1.20.3,)",
+ "recommendedVersion": "1.20.3"
+ },
+ {
+ "name": "uiautomator2",
+ "version": "[4.2.1,)",
+ "recommendedVersion": "4.2.1"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/dotnet.Tests/CommandTests/Workload/Install/GivenDotnetWorkloadInstall.cs b/test/dotnet.Tests/CommandTests/Workload/Install/GivenDotnetWorkloadInstall.cs
index debf87db5f45..ee70a4ea5374 100644
--- a/test/dotnet.Tests/CommandTests/Workload/Install/GivenDotnetWorkloadInstall.cs
+++ b/test/dotnet.Tests/CommandTests/Workload/Install/GivenDotnetWorkloadInstall.cs
@@ -11,6 +11,7 @@
using Microsoft.Extensions.EnvironmentAbstractions;
using Microsoft.NET.Sdk.WorkloadManifestReader;
using Microsoft.DotNet.Cli.Commands.Workload.Install;
+using Microsoft.DotNet.Cli.Commands.Workload.Install.WorkloadInstallRecords;
using Microsoft.DotNet.Cli.Commands.Workload;
using Microsoft.DotNet.Cli.Commands.Workload.Config;
using Microsoft.DotNet.Cli.Commands;
@@ -186,6 +187,78 @@ public void GivenNoWorkloadsInstalledInfoOptionRemarksOnThat()
_reporter.Lines.Should().Contain("There are no installed workloads to display.");
}
+ [Fact]
+ public void GivenInstalledWorkloadsInfoOptionShowsDependencies()
+ {
+ // Test that workload --info displays dependencies from WorkloadDependencies.json
+ _reporter.Clear();
+ var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
+ var dotnetRoot = Path.Combine(testDirectory, "dotnet");
+
+ // Create mock workload installation record repository that returns xamarin-android as installed
+ var mockInstallRecordRepo = new MockWorkloadInstallRecordRepository(new[] { new WorkloadId("xamarin-android") });
+ var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), dotnetRoot);
+
+ WorkloadInfoHelper workloadInfoHelper = new WorkloadInfoHelper(
+ isInteractive: false,
+ workloadResolver: workloadResolver,
+ workloadRecordRepo: mockInstallRecordRepo);
+ workloadInfoHelper.ShowWorkloadsInfo(reporter: _reporter);
+
+ // Verify workload is listed
+ var output = string.Join(Environment.NewLine, _reporter.Lines);
+ output.Should().Contain("[xamarin-android]");
+
+ // Verify dependencies are shown from WorkloadDependencies.json
+ output.Should().Contain("Dependencies (jdk):");
+ output.Should().Contain("[11.0,18.0)"); // Version value (label is padded)
+ output.Should().Contain("11.0.12"); // Recommended Version value
+
+ output.Should().Contain("Dependencies (androidsdk):");
+ output.Should().Contain("Android SDK Build-Tools 30");
+ output.Should().Contain("build-tools;30.0.3");
+ output.Should().Contain("Android SDK Platform-Tools");
+ output.Should().Contain("platform-tools");
+ output.Should().Contain("31.0.3"); // Recommended Version from sdkPackage wrapper
+ output.Should().Contain("Android Emulator (optional)");
+ output.Should().Contain("emulator");
+
+ // Verify RID-keyed id is resolved to platform-specific value
+ output.Should().Contain("Google APIs System Image (optional)");
+ output.Should().Contain("system-images;android-35;google_apis;");
+
+ // Verify appium drivers array is shown
+ output.Should().Contain("Dependencies (appium):");
+ output.Should().Contain("[2.17.1,)"); // Version value
+ output.Should().Contain("windows");
+ output.Should().Contain("xcuitest");
+ output.Should().Contain("mac2");
+ output.Should().Contain("uiautomator2");
+
+ // Verify "workload" category is skipped (it's metadata, not a dependency)
+ output.Should().NotContain("Dependencies (workload):");
+ output.Should().NotContain("This should be skipped");
+
+ // Verify optional: false does not show "(optional)"
+ output.Should().Contain("Not Optional Item");
+ output.Should().NotContain("Not Optional Item (optional)");
+ }
+
+ private class MockWorkloadInstallRecordRepository : IWorkloadInstallationRecordRepository
+ {
+ private readonly IEnumerable _installedWorkloads;
+
+ public MockWorkloadInstallRecordRepository(IEnumerable installedWorkloads)
+ {
+ _installedWorkloads = installedWorkloads;
+ }
+
+ public IEnumerable GetInstalledWorkloads(SdkFeatureBand sdkFeatureBand) => _installedWorkloads;
+ public void WriteWorkloadInstallationRecord(WorkloadId workloadId, SdkFeatureBand sdkFeatureBand) { }
+ public void DeleteWorkloadInstallationRecord(WorkloadId workloadId, SdkFeatureBand sdkFeatureBand) { }
+ public IEnumerable GetFeatureBandsWithInstallationRecords() => Array.Empty();
+ }
+
[Fact]
public void GivenBadOptionWorkloadBaseInformsRequiredCommandWasNotProvided()
{