diff --git a/src/Microsoft.DotNet.Wpf/src/WPFProjectGenerator/App.config b/src/Microsoft.DotNet.Wpf/src/WPFProjectGenerator/App.config new file mode 100644 index 00000000000..ad5dd5db3e8 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/WPFProjectGenerator/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Microsoft.DotNet.Wpf/src/WPFProjectGenerator/Program.cs b/src/Microsoft.DotNet.Wpf/src/WPFProjectGenerator/Program.cs new file mode 100644 index 00000000000..21c267dfe3f --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/WPFProjectGenerator/Program.cs @@ -0,0 +1,120 @@ +// See https://aka.ms/new-console-template for more information +//Console.WriteLine("Hello, World!"); +using System.Configuration; +using System.Diagnostics; +using System.Xml.Linq; + + + +string projectName; +string targetFramework; +string[] tfmName; + +List? allTFMs = null; + +string? tfmsValue = ConfigurationManager.AppSettings["tfms"]; + +if (string.IsNullOrEmpty(tfmsValue)) +{ + Console.WriteLine("The 'tfms' key is missing or has no value."); +} +else +{ + allTFMs = [.. tfmsValue.Split(';')]; +} +if (allTFMs != null) +{ + if (allTFMs.Count > 0) + { + string rootPath = Directory.GetCurrentDirectory() + "TFMProjects"; + if ((Directory.Exists(rootPath))) + { + Directory.Delete(rootPath, true); + Directory.CreateDirectory(rootPath); + } + for (int i = 0; i < allTFMs.Count; i++) + { + tfmName = allTFMs[i].Split('.'); + projectName = "TestSampleWPF" + tfmName[0].ToString().ToUpper(System.Globalization.CultureInfo.CurrentCulture); + targetFramework = allTFMs[i]; + // Create the project + CreateProject(projectName, targetFramework); + } + } +} + + + +static void CreateProject(string projectName, string targetFramework) +{ + // Define project path + string rootPath = Directory.GetCurrentDirectory() + "TFMProjects"; + if (!(Directory.Exists(rootPath))) + { + Directory.CreateDirectory(rootPath); + } + + + string projectPath = Path.Combine(rootPath, projectName); + + // Create project directory + Directory.CreateDirectory(projectPath); + + // Command to create a new project + string createProjectCommand = $"dotnet new wpf -n {projectName} --framework {targetFramework}"; + + // Start the process to create the project + ProcessStartInfo startInfo = new("cmd", "/c " + createProjectCommand) + { + WorkingDirectory = projectPath, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + // Check if startInfo is null + if (startInfo == null) + { + Console.WriteLine("ProcessStartInfo is null, cannot start the process."); + return; + } + + using (Process? process = Process.Start(startInfo)) + { + if (process == null) + { + Console.WriteLine("Failed to start the process."); + return; + } + process.WaitForExit(); + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + + Console.WriteLine(output); + if (!string.IsNullOrEmpty(error)) + { + Console.WriteLine($"Error: {error}"); + } + } + + Console.WriteLine($"Project '{projectName}' created with target framework '{targetFramework}'."); + //// Path to the .csproj file + //string csprojFilePath = Path.Combine(projectPath, $"{Path.GetFileName(projectPath)}.csproj"); + + //if (File.Exists(csprojFilePath)) + //{ + // // Load the .csproj file as an XML document + // XDocument csprojDoc = XDocument.Load(csprojFilePath); + + // // Check if the WindowsBase reference exists, if not, add it + // var itemGroup = csprojDoc.Descendants("ItemGroup").FirstOrDefault(); + // if (itemGroup != null && !itemGroup.Descendants("Reference").Any(r => r.Attribute("Include")?.Value == "WindowsBase")) + // { + // // Add the WindowsBase reference manually + // itemGroup.Add(new XElement("Reference", new XAttribute("Include", "WindowsBase"))); + // } + + // // Save the changes back to the .csproj file + // csprojDoc.Save(csprojFilePath); + //} +} diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/TargetFramework.Tests/XUnitTFMTest.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/TargetFramework.Tests/XUnitTFMTest.cs new file mode 100644 index 00000000000..d2f9d7a9cc4 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/TargetFramework.Tests/XUnitTFMTest.cs @@ -0,0 +1,261 @@ +// 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.Generic; +//using System; +//using System.Diagnostics; +//using System.IO; +//using System.Linq; +//using System.Threading; +using System.Diagnostics; +using System.Xml.Linq; +using Microsoft.Extensions.Configuration; +using Xunit; + +namespace TargetFramework.Tests; + +public class XUnitTFMTest +{ + + private static IConfiguration? s_configuration = InitializeConfiguration(); + //private static readonly string s_wpfProjectDirectory = InitializeWpfProjectDirectory(); + private static readonly string s_appPath = InitializeAppPath(); + private static readonly string s_newTargetFramework = InitializeTargetFramework(); + //private static readonly string? s_wpfProjectDirectory = null; + static XUnitTFMTest() + { + CreateTFMProjects(); + } + private static IConfiguration InitializeConfiguration() + + { + s_configuration = new ConfigurationBuilder() + .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) // Set base path + .AddJsonFile("app.json", optional: false, reloadOnChange: true) // Load appsettings.json + .Build(); + return s_configuration; + } + // Static methods to initialize fields + //private static string InitializeWpfProjectDirectory() + //{ + // if (s_configuration != null) + // { + // string? s_currentDir = Directory.GetCurrentDirectory(); + // string? wpfProjectDirectory = s_configuration["WpfProjectDirectory"]; + // if (wpfProjectDirectory != null && s_currentDir != null) + // { + // DirectoryInfo? parentDir = Directory.GetParent(s_currentDir); + // return parentDir + wpfProjectDirectory; + // } + // } + // return string.Empty; + //} + + private static string InitializeAppPath() + { + if (s_configuration != null) + { + string? s_currentDir = Directory.GetCurrentDirectory(); + string? appPath = s_configuration["appPath"]; + if (appPath != null && s_currentDir != null) + { + return s_currentDir + appPath; + } + } + return string.Empty; + } + + private static string InitializeTargetFramework() + { + return s_configuration?["latestTargetFramework"] ?? string.Empty; + } + + public static IEnumerable GetTestData() + { + string? s_wpfProjectDirectory = null; + if (s_configuration != null) + { + string? s_currentDir = Directory.GetCurrentDirectory(); + string? wpfProjectDirectory = s_configuration["WpfProjectDirectory"]; + if (wpfProjectDirectory != null && s_currentDir != null) + { + DirectoryInfo? parentDir = Directory.GetParent(s_currentDir); + s_wpfProjectDirectory = parentDir + wpfProjectDirectory; + } + } + if (s_wpfProjectDirectory != null) + { + foreach (var filename in Directory.GetFiles(s_wpfProjectDirectory, "*.csproj", SearchOption.AllDirectories)) + { + yield return new object[] { filename.ToString() }; + } + } + else + { + yield return (object[])Enumerable.Empty(); + } + + } + + [Theory] + [MemberData(nameof(GetTestData))] + public void TestWPFApp(string filename) + { + var publishResult=PublishWPFApp(filename); + Assert.True(publishResult, "WPF Application publish failed."); + //commenting as the tests are failing due to windowsbase.dll error + + //var launchResult = LaunchWPFApp(filename); + //Assert.True(launchResult, "WPF Application launch failed."); + //ChangeTargetFramework(filename); + //publishResult = PublishWPFApp(filename); + //Assert.True(publishResult, "WPF Application publish failed."); + //launchResult = LaunchWPFApp(filename); + //Assert.True(launchResult, "WPF Application launch failed."); + + } + + private static bool PublishWPFApp(string filename) + { + string? projectPath = null; + string? publishPath = null; + if (filename != null) + { + projectPath = Path.GetDirectoryName(filename); + } + + if (projectPath != null) + { + publishPath = Path.Combine(projectPath, "publish"); + } + + // Act + var result=false; + if (publishPath != null && projectPath != null) + { + result = RunDotnetPublish(projectPath, publishPath); + } + return result; + // Assert.True(Directory.Exists(publishPath)); + + } + + private static bool RunDotnetPublish(string projectPath, string publishPath) + { + // Set up the process start information to run the 'dotnet publish' command + var startInfo = new ProcessStartInfo + { + FileName = "dotnet", + Arguments = $"publish \"{projectPath}\" -c Release -r win-x64 --self-contained -o \"{publishPath}\"", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + // Start the process + using var process = Process.Start(startInfo); + if (process == null) + { + return false; + } + + // Read output and error streams + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + + process.WaitForExit(); + + // Optionally log output and errors + Console.WriteLine(output); + Console.WriteLine(error); + + return process.ExitCode == 0; // Return true if the exit code is 0 (success) + } + + private static bool LaunchWPFApp(string filename) + { + string? publishPath = null; + string? exePath = null; + string? directoryPath = Path.GetDirectoryName(filename); + string? withoutExtension = Path.GetFileNameWithoutExtension(filename); + if (directoryPath != null) + { + publishPath = Path.Combine(directoryPath, "publish"); + } + if (publishPath != null) + { + exePath = Path.Combine(publishPath, withoutExtension + ".exe"); + } + + // Start the WPF application + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = exePath, + UseShellExecute = true, + } + }; + + process.Start(); + + // Optionally wait for a moment to ensure the app is up + Thread.Sleep(2000); + return process.ExitCode == 0; + } + private static void CreateTFMProjects() + { + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = s_appPath, + UseShellExecute = true, + } + }; + process.Start(); + // Optionally wait for a moment to ensure the app is up + Thread.Sleep(2000); + //Assert.False(process.HasExited); + process.WaitForExit(); + process.Kill(); + } + + + //Change the TFM to latest version of .Net + private static void ChangeTargetFramework(string WpfProjectPath) + { + if (!File.Exists(WpfProjectPath)) + { + Console.WriteLine("Project file not found."); + return; + } + + // Load the project file + XDocument doc = XDocument.Load(WpfProjectPath); + XElement? propertyGroup = doc.Descendants("PropertyGroup").FirstOrDefault(); + + if (propertyGroup != null && s_newTargetFramework != null) + { + XElement? targetFrameworkElement = propertyGroup.Elements("TargetFramework").FirstOrDefault(); + if (targetFrameworkElement != null) + { + targetFrameworkElement.Value = s_newTargetFramework; + } + else + { + propertyGroup.Add(new XElement("TargetFramework", s_newTargetFramework)); + } + + // Save the changes + doc.Save(WpfProjectPath); + Console.WriteLine($"Target framework changed to '{s_newTargetFramework}' in '{WpfProjectPath}'."); + } + else + { + Console.WriteLine("No PropertyGroup found in the project file."); + } + } + +} diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/TargetFramework.Tests/app.json b/src/Microsoft.DotNet.Wpf/tests/UnitTests/TargetFramework.Tests/app.json new file mode 100644 index 00000000000..730392f0858 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/TargetFramework.Tests/app.json @@ -0,0 +1,5 @@ +{ + "appPath": "\\WPFProjectGenerator.exe", + "WpfProjectDirectory": "\\net10.0-windowsTFMProjects", + "latestTargetFramework": "net10.0-windows" +}