// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Test.BA
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;
using WixToolset.BootstrapperApplicationApi;
///
/// A minimal UX used for testing.
///
public class TestBA : BootstrapperApplication
{
private const string BurnBundleVersionVariable = "WixBundleVersion";
private Form dummyWindow;
private IntPtr windowHandle;
private LaunchAction action;
private readonly ManualResetEvent wait;
private int result;
private string updateBundlePath;
private bool allowAcquireAfterValidationFailure;
private bool forceKeepRegistration;
private bool immediatelyQuit;
private bool quitAfterDetect;
private bool explicitlyElevateAndPlanFromOnElevateBegin;
private int redetectRemaining;
private int sleepDuringCache;
private int cancelCacheAtProgress;
private int sleepDuringExecute;
private int cancelExecuteAtProgress;
private string cancelExecuteActionName;
private int cancelOnProgressAtProgress;
private int retryExecuteFilesInUse;
private bool rollingBack;
private IBootstrapperCommand Command { get; set; }
private IEngine Engine => this.engine;
///
/// Initializes test user experience.
///
public TestBA()
{
this.wait = new ManualResetEvent(false);
}
///
/// Get the version of the install.
///
public string Version { get; private set; }
///
/// Indicates if DetectUpdate found a newer version to update.
///
private bool UpdateAvailable { get; set; }
protected override void OnCreate(CreateEventArgs args)
{
base.OnCreate(args);
this.Command = args.Command;
}
///
/// UI Thread entry point for TestUX.
///
protected override void OnStartup(StartupEventArgs args)
{
string immediatelyQuit = this.ReadPackageAction(null, "ImmediatelyQuit");
if (!String.IsNullOrEmpty(immediatelyQuit) && Boolean.TryParse(immediatelyQuit, out this.immediatelyQuit) && this.immediatelyQuit)
{
this.Engine.Quit(0);
return;
}
this.action = this.Command.Action;
this.TestVariables();
this.Version = this.engine.GetVariableVersion(BurnBundleVersionVariable);
this.Log("Version: {0}", this.Version);
List verifyArguments = this.ReadVerifyArguments();
IBootstrapperApplicationData baManifest = new BootstrapperApplicationData();
IMbaCommand mbaCommand = this.Command.ParseCommandLine();
mbaCommand.SetOverridableVariables(baManifest.Bundle.OverridableVariables, this.engine);
foreach (string arg in mbaCommand.UnknownCommandLineArgs)
{
// If we're not in the update already, process the updatebundle.
if (this.Command.Relation != RelationType.Update && arg.StartsWith("-updatebundle:", StringComparison.OrdinalIgnoreCase))
{
this.updateBundlePath = arg.Substring(14);
FileInfo info = new FileInfo(this.updateBundlePath);
this.Engine.SetUpdate(this.updateBundlePath, null, info.Length, UpdateHashType.None, null, null);
this.UpdateAvailable = true;
this.action = LaunchAction.UpdateReplaceEmbedded;
}
else if (this.Command.Relation != RelationType.Update && arg.StartsWith("-checkupdate", StringComparison.OrdinalIgnoreCase))
{
this.action = LaunchAction.UpdateReplace;
}
verifyArguments.Remove(arg);
}
this.Log("Action: {0}", this.action);
// If there are any verification arguments left, error out.
if (0 < verifyArguments.Count)
{
foreach (string expectedArg in verifyArguments)
{
this.Log("Failure. Expected command-line to have argument: {0}", expectedArg);
}
this.Engine.Quit(-1);
return;
}
base.OnStartup(args);
string redetect = this.ReadPackageAction(null, "RedetectCount");
if (String.IsNullOrEmpty(redetect) || !Int32.TryParse(redetect, out var redetectCount))
{
redetectCount = 0;
}
string allowAcquireAfterValidationFailure = this.ReadPackageAction(null, "AllowAcquireAfterValidationFailure");
if (String.IsNullOrEmpty(allowAcquireAfterValidationFailure) || !Boolean.TryParse(allowAcquireAfterValidationFailure, out this.allowAcquireAfterValidationFailure))
{
this.allowAcquireAfterValidationFailure = false;
}
string explicitlyElevateAndPlanFromOnElevateBegin = this.ReadPackageAction(null, "ExplicitlyElevateAndPlanFromOnElevateBegin");
if (String.IsNullOrEmpty(explicitlyElevateAndPlanFromOnElevateBegin) || !Boolean.TryParse(explicitlyElevateAndPlanFromOnElevateBegin, out this.explicitlyElevateAndPlanFromOnElevateBegin))
{
this.explicitlyElevateAndPlanFromOnElevateBegin = false;
}
string forceKeepRegistration = this.ReadPackageAction(null, "ForceKeepRegistration");
if (String.IsNullOrEmpty(forceKeepRegistration) || !Boolean.TryParse(forceKeepRegistration, out this.forceKeepRegistration))
{
this.forceKeepRegistration = false;
}
string quitAfterDetect = this.ReadPackageAction(null, "QuitAfterDetect");
if (String.IsNullOrEmpty(quitAfterDetect) || !Boolean.TryParse(quitAfterDetect, out this.quitAfterDetect))
{
this.quitAfterDetect = false;
}
this.ImportContainerSources();
this.ImportPayloadSources();
this.wait.WaitOne();
if (this.action == LaunchAction.Help)
{
this.Log("This is a BA for automated testing");
this.ShutdownUiThread(0);
return;
}
this.redetectRemaining = redetectCount;
for (int i = -1; i < redetectCount; i++)
{
this.Engine.Detect(this.windowHandle);
}
}
protected override void Run()
{
using (this.dummyWindow = new Form())
{
this.windowHandle = this.dummyWindow.Handle;
this.Log("Running TestBA application");
this.wait.Set();
Application.Run();
this.dummyWindow = null;
}
var exitCode = this.result;
if ((exitCode & 0xFFFF0000) == unchecked(0x80070000))
{
exitCode &= 0xFFFF; // return plain old Win32 error, not HRESULT.
}
this.Engine.Quit(exitCode);
}
private void ShutdownUiThread(int? exitCode = null)
{
try
{
if (exitCode.HasValue)
{
this.result = exitCode.Value;
}
this.dummyWindow?.Invoke(new Action(Application.ExitThread));
}
catch (Exception e)
{
this.Log("Failed to shutdown TestBA window, exception: {0}", e.Message);
}
}
protected override void OnDetectUpdateBegin(DetectUpdateBeginEventArgs args)
{
this.Log("OnDetectUpdateBegin");
if (LaunchAction.UpdateReplaceEmbedded == this.action || LaunchAction.UpdateReplace == this.action)
{
args.Skip = false;
}
}
protected override void OnDetectUpdate(DetectUpdateEventArgs e)
{
// The list of updates is sorted in descending version, so the first callback should be the largest update available.
// This update should be either larger than ours (so we are out of date), the same as ours (so we are current)
// or smaller than ours (we have a private build).
// Enumerate all of the updates anyway in case something's broken.
this.Log(String.Format("Potential update v{0} from '{1}'; current version: v{2}", e.Version, e.UpdateLocation, this.Version));
if (!this.UpdateAvailable && this.Engine.CompareVersions(e.Version, this.Version) > 0)
{
this.Log(String.Format("Selected update v{0}", e.Version));
this.Engine.SetUpdate(null, e.UpdateLocation, e.Size, e.HashAlgorithm, e.Hash, null);
this.UpdateAvailable = true;
}
}
protected override void OnDetectUpdateComplete(DetectUpdateCompleteEventArgs e)
{
this.Log("OnDetectUpdateComplete");
// Failed to process an update, allow the existing bundle to still install.
if (!Hresult.Succeeded(e.Status))
{
this.Log(String.Format("Failed to locate an update, status of 0x{0:X8}, updates disabled.", e.Status));
e.IgnoreError = true; // But continue on...
}
}
protected override void OnDetectComplete(DetectCompleteEventArgs args)
{
this.result = args.Status;
if (Hresult.Succeeded(this.result) &&
(this.UpdateAvailable || LaunchAction.UpdateReplaceEmbedded != this.action && LaunchAction.UpdateReplace != this.action))
{
if (this.redetectRemaining > 0)
{
this.Log("Completed detection phase: {0} re-runs remaining", this.redetectRemaining--);
}
else if (this.quitAfterDetect)
{
this.ShutdownUiThread();
}
else if (this.explicitlyElevateAndPlanFromOnElevateBegin)
{
this.Engine.Elevate(this.windowHandle);
}
else
{
this.Engine.Plan(this.action);
}
}
else
{
this.ShutdownUiThread();
}
}
protected override void OnDetectRelatedBundle(DetectRelatedBundleEventArgs args)
{
this.Log("OnDetectRelatedBundle() - id: {0}, missing from cache: {1}", args.ProductCode, args.MissingFromCache);
}
protected override void OnElevateBegin(ElevateBeginEventArgs args)
{
if (this.explicitlyElevateAndPlanFromOnElevateBegin)
{
this.Engine.Plan(this.action);
// Simulate showing some UI since these tests won't actually show the UAC prompt.
MessagePump.ProcessMessages(10);
}
}
protected override void OnPlanPackageBegin(PlanPackageBeginEventArgs args)
{
RequestState state;
string action = this.ReadPackageAction(args.PackageId, "Requested");
if (TryParseEnum(action, out state))
{
args.State = state;
}
BOOTSTRAPPER_CACHE_TYPE cacheType;
string cacheAction = this.ReadPackageAction(args.PackageId, "CacheRequested");
if (TryParseEnum(cacheAction, out cacheType))
{
args.CacheType = cacheType;
}
this.Log("OnPlanPackageBegin() - id: {0}, currentState: {1}, defaultState: {2}, requestedState: {3}, defaultCache: {4}, requestedCache: {5}", args.PackageId, args.CurrentState, args.RecommendedState, args.State, args.RecommendedCacheType, args.CacheType);
}
protected override void OnPlanPatchTarget(PlanPatchTargetEventArgs args)
{
RequestState state;
string action = this.ReadPackageAction(args.PackageId, "Requested");
if (TryParseEnum(action, out state))
{
args.State = state;
}
}
protected override void OnPlanMsiFeature(PlanMsiFeatureEventArgs args)
{
FeatureState state;
string action = this.ReadFeatureAction(args.PackageId, args.FeatureId, "Requested");
if (TryParseEnum(action, out state))
{
args.State = state;
}
this.Log("OnPlanMsiFeature() - id: {0}, defaultState: {1}, requestedState: {2}", args.PackageId, args.RecommendedState, args.State);
}
protected override void OnPlanComplete(PlanCompleteEventArgs args)
{
this.result = args.Status;
if (Hresult.Succeeded(this.result))
{
this.Engine.Apply(this.windowHandle);
}
else
{
this.ShutdownUiThread();
}
}
protected override void OnCachePackageBegin(CachePackageBeginEventArgs args)
{
this.Log("OnCachePackageBegin() - package: {0}, payloads to cache: {1}", args.PackageId, args.CachePayloads);
string slowProgress = this.ReadPackageAction(args.PackageId, "SlowCache");
if (String.IsNullOrEmpty(slowProgress) || !Int32.TryParse(slowProgress, out this.sleepDuringCache))
{
this.sleepDuringCache = 0;
}
else
{
this.Log(" SlowCache: {0}", this.sleepDuringCache);
}
string cancelCache = this.ReadPackageAction(args.PackageId, "CancelCacheAtProgress");
if (String.IsNullOrEmpty(cancelCache) || !Int32.TryParse(cancelCache, out this.cancelCacheAtProgress))
{
this.cancelCacheAtProgress = -1;
}
else
{
this.Log(" CancelCacheAtProgress: {0}", this.cancelCacheAtProgress);
}
}
protected override void OnCachePackageNonVitalValidationFailure(CachePackageNonVitalValidationFailureEventArgs args)
{
if (this.allowAcquireAfterValidationFailure)
{
args.Action = BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION.Acquire;
}
this.Log("OnCachePackageNonVitalValidationFailure() - id: {0}, default: {1}, requested: {2}", args.PackageId, args.Recommendation, args.Action);
}
protected override void OnCacheAcquireProgress(CacheAcquireProgressEventArgs args)
{
this.Log("OnCacheAcquireProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage);
if (this.cancelCacheAtProgress >= 0 && this.cancelCacheAtProgress <= args.Progress)
{
args.Cancel = true;
this.Log("OnCacheAcquireProgress(cancel)");
}
else if (this.sleepDuringCache > 0)
{
this.Log("OnCacheAcquireProgress(sleep {0})", this.sleepDuringCache);
Thread.Sleep(this.sleepDuringCache);
}
}
protected override void OnCacheContainerOrPayloadVerifyProgress(CacheContainerOrPayloadVerifyProgressEventArgs args)
{
this.Log("OnCacheContainerOrPayloadVerifyProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage);
}
protected override void OnCachePayloadExtractProgress(CachePayloadExtractProgressEventArgs args)
{
this.Log("OnCachePayloadExtractProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage);
}
protected override void OnCacheVerifyProgress(CacheVerifyProgressEventArgs args)
{
this.Log("OnCacheVerifyProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%, step: {5}", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage, args.Step);
}
protected override void OnExecutePackageBegin(ExecutePackageBeginEventArgs args)
{
this.Log("OnExecutePackageBegin() - package: {0}, rollback: {1}", args.PackageId, !args.ShouldExecute);
this.rollingBack = !args.ShouldExecute;
string slowProgress = this.ReadPackageAction(args.PackageId, "SlowExecute");
if (String.IsNullOrEmpty(slowProgress) || !Int32.TryParse(slowProgress, out this.sleepDuringExecute))
{
this.sleepDuringExecute = 0;
}
else
{
this.Log(" SlowExecute: {0}", this.sleepDuringExecute);
}
string cancelExecute = this.ReadPackageAction(args.PackageId, "CancelExecuteAtProgress");
if (String.IsNullOrEmpty(cancelExecute) || !Int32.TryParse(cancelExecute, out this.cancelExecuteAtProgress))
{
this.cancelExecuteAtProgress = -1;
}
else
{
this.Log(" CancelExecuteAtProgress: {0}", this.cancelExecuteAtProgress);
}
this.cancelExecuteActionName = this.ReadPackageAction(args.PackageId, "CancelExecuteAtActionStart");
if (!String.IsNullOrEmpty(this.cancelExecuteActionName))
{
this.Log(" CancelExecuteAtActionState: {0}", this.cancelExecuteActionName);
}
string cancelOnProgressAtProgress = this.ReadPackageAction(args.PackageId, "CancelOnProgressAtProgress");
if (String.IsNullOrEmpty(cancelOnProgressAtProgress) || !Int32.TryParse(cancelOnProgressAtProgress, out this.cancelOnProgressAtProgress))
{
this.cancelOnProgressAtProgress = -1;
}
else
{
this.Log(" CancelOnProgressAtProgress: {0}", this.cancelOnProgressAtProgress);
}
string retryBeforeCancel = this.ReadPackageAction(args.PackageId, "RetryExecuteFilesInUse");
if (String.IsNullOrEmpty(retryBeforeCancel) || !Int32.TryParse(retryBeforeCancel, out this.retryExecuteFilesInUse))
{
this.retryExecuteFilesInUse = 0;
}
else
{
this.Log(" RetryExecuteFilesInUse: {0}", this.retryExecuteFilesInUse);
}
}
protected override void OnExecutePackageComplete(ExecutePackageCompleteEventArgs args)
{
bool logTestRegistryValue;
string recordTestRegistryValue = this.ReadPackageAction(args.PackageId, "RecordTestRegistryValue");
if (!String.IsNullOrEmpty(recordTestRegistryValue) && Boolean.TryParse(recordTestRegistryValue, out logTestRegistryValue) && logTestRegistryValue)
{
var value = this.ReadTestRegistryValue(args.PackageId);
this.Log("TestRegistryValue: {0}, {1}, Version, '{2}'", this.rollingBack ? "Rollback" : "Execute", args.PackageId, value);
}
}
protected override void OnExecuteProcessCancel(ExecuteProcessCancelEventArgs args)
{
BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION action;
string actionValue = this.ReadPackageAction(args.PackageId, "ProcessCancelAction");
if (actionValue != null && TryParseEnum(actionValue, out action))
{
args.Action = action;
}
if (args.Action == BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION.Abandon)
{
// Kill process to make sure it doesn't affect other tests.
try
{
using (Process process = Process.GetProcessById(args.ProcessId))
{
if (process != null)
{
process.Kill();
}
}
}
catch (Exception e)
{
this.Log("Failed to kill process {0}: {1}", args.ProcessId, e);
Thread.Sleep(5000);
}
}
this.Log("OnExecuteProcessCancel({0})", args.Action);
}
protected override void OnExecuteFilesInUse(ExecuteFilesInUseEventArgs args)
{
this.Log("OnExecuteFilesInUse() - package: {0}, source: {1}, retries remaining: {2}, data: {3}", args.PackageId, args.Source, this.retryExecuteFilesInUse, String.Join(", ", args.Files.ToArray()));
if (this.retryExecuteFilesInUse > 0)
{
--this.retryExecuteFilesInUse;
args.Result = Result.Retry;
}
else
{
args.Result = Result.Cancel;
}
}
protected override void OnExecuteMsiMessage(ExecuteMsiMessageEventArgs args)
{
this.Log("OnExecuteMsiMessage() - MessageType: {0}, Message: {1}, Data: '{2}'", args.MessageType, args.Message, String.Join("','", args.Data.ToArray()));
if (!String.IsNullOrEmpty(this.cancelExecuteActionName) && args.MessageType == InstallMessage.ActionStart &&
args.Data.Count > 0 && args.Data[0] == this.cancelExecuteActionName)
{
this.Log("OnExecuteMsiMessage(cancelNextProgress)");
this.cancelExecuteAtProgress = 0;
}
}
protected override void OnExecuteProgress(ExecuteProgressEventArgs args)
{
this.Log("OnExecuteProgress() - package: {0}, progress: {1}%, overall progress: {2}%", args.PackageId, args.ProgressPercentage, args.OverallPercentage);
if (this.cancelExecuteAtProgress >= 0 && this.cancelExecuteAtProgress <= args.ProgressPercentage)
{
args.Cancel = true;
this.Log("OnExecuteProgress(cancel)");
}
else if (this.sleepDuringExecute > 0)
{
this.Log("OnExecuteProgress(sleep {0})", this.sleepDuringExecute);
Thread.Sleep(this.sleepDuringExecute);
}
}
protected override void OnExecutePatchTarget(ExecutePatchTargetEventArgs args)
{
this.Log("OnExecutePatchTarget - Patch Package: {0}, Target Product Code: {1}", args.PackageId, args.TargetProductCode);
}
protected override void OnProgress(ProgressEventArgs args)
{
this.Log("OnProgress() - progress: {0}%, overall progress: {1}%", args.ProgressPercentage, args.OverallPercentage);
if (this.Command.Display == Display.Embedded)
{
this.Engine.SendEmbeddedProgress(args.ProgressPercentage, args.OverallPercentage);
}
if (this.cancelOnProgressAtProgress >= 0 && this.cancelOnProgressAtProgress <= args.OverallPercentage)
{
args.Cancel = true;
this.Log("OnProgress(cancel)");
}
}
protected override void OnApplyBegin(ApplyBeginEventArgs args)
{
this.cancelOnProgressAtProgress = -1;
this.cancelExecuteAtProgress = -1;
this.cancelCacheAtProgress = -1;
this.rollingBack = false;
}
protected override void OnApplyComplete(ApplyCompleteEventArgs args)
{
// Output what the privileges are now.
this.Log("After elevation: WixBundleElevated = {0}", this.Engine.GetVariableNumeric("WixBundleElevated"));
this.ShutdownUiThread(args.Status);
}
protected override void OnUnregisterBegin(UnregisterBeginEventArgs args)
{
if (this.forceKeepRegistration && args.RegistrationType == RegistrationType.None)
{
args.RegistrationType = RegistrationType.InProgress;
}
this.Log("OnUnregisterBegin, default: {0}, requested: {1}", args.RecommendedRegistrationType, args.RegistrationType);
}
private void TestVariables()
{
// First make sure we can check and get standard variables of each type.
if (this.Engine.ContainsVariable("WindowsFolder"))
{
string value = this.Engine.GetVariableString("WindowsFolder");
this.Engine.Log(LogLevel.Verbose, String.Format("TEST: Successfully retrieved a string variable: WindowsFolder '{0}'", value));
}
else
{
throw new Exception("Engine did not define a standard variable: WindowsFolder");
}
if (this.Engine.ContainsVariable("NTProductType"))
{
long value = this.Engine.GetVariableNumeric("NTProductType");
this.Engine.Log(LogLevel.Verbose, String.Format("TEST: Successfully retrieved a numeric variable: NTProductType '{0}'", value));
}
else
{
throw new Exception("Engine did not define a standard variable: NTProductType");
}
if (this.Engine.ContainsVariable("VersionMsi"))
{
string value = this.Engine.GetVariableVersion("VersionMsi");
this.Engine.Log(LogLevel.Verbose, String.Format("TEST: Successfully retrieved a version variable: VersionMsi '{0}'", value));
}
else
{
throw new Exception("Engine did not define a standard variable: VersionMsi");
}
// Now validate that Contians returns false for non-existant variables of each type.
if (this.Engine.ContainsVariable("TestStringVariableShouldNotExist"))
{
throw new Exception("Engine defined a variable that should not exist: TestStringVariableShouldNotExist");
}
else
{
this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent string variable: TestStringVariableShouldNotExist");
}
if (this.Engine.ContainsVariable("TestNumericVariableShouldNotExist"))
{
throw new Exception("Engine defined a variable that should not exist: TestNumericVariableShouldNotExist");
}
else
{
this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent numeric variable: TestNumericVariableShouldNotExist");
}
if (this.Engine.ContainsVariable("TestVersionVariableShouldNotExist"))
{
throw new Exception("Engine defined a variable that should not exist: TestVersionVariableShouldNotExist");
}
else
{
this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent version variable: TestVersionVariableShouldNotExist");
}
// Output what the initially run privileges were.
this.Engine.Log(LogLevel.Verbose, String.Format("TEST: WixBundleElevated = {0}", this.Engine.GetVariableNumeric("WixBundleElevated")));
}
private void Log(string format, params object[] args)
{
string relation = this.Command.Relation != RelationType.None ? String.Concat(" (", this.Command.Relation.ToString().ToLowerInvariant(), ")") : String.Empty;
string message = String.Format(format, args);
this.Engine.Log(LogLevel.Standard, String.Concat("TESTBA", relation, ": ", message));
}
private void ImportContainerSources()
{
string testName = this.Engine.GetVariableString("TestGroupName");
using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}\container", testName)))
{
if (testKey == null)
{
return;
}
foreach (var containerId in testKey.GetSubKeyNames())
{
using (RegistryKey subkey = testKey.OpenSubKey(containerId))
{
string initialSource = subkey == null ? null : subkey.GetValue("InitialLocalSource") as string;
if (initialSource != null)
{
this.Engine.SetLocalSource(containerId, null, initialSource);
}
}
}
}
}
private void ImportPayloadSources()
{
string testName = this.Engine.GetVariableString("TestGroupName");
using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}\payload", testName)))
{
if (testKey == null)
{
return;
}
foreach (var payloadId in testKey.GetSubKeyNames())
{
using (RegistryKey subkey = testKey.OpenSubKey(payloadId))
{
string initialSource = subkey == null ? null : subkey.GetValue("InitialLocalSource") as string;
if (initialSource != null)
{
this.Engine.SetLocalSource(null, payloadId, initialSource);
}
}
}
}
}
private List ReadVerifyArguments()
{
string testName = this.Engine.GetVariableString("TestGroupName");
using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}", testName)))
{
string verifyArguments = testKey == null ? null : testKey.GetValue("VerifyArguments") as string;
return verifyArguments == null ? new List() : new List(verifyArguments.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
}
}
private string ReadPackageAction(string packageId, string state)
{
string testName = this.Engine.GetVariableString("TestGroupName");
using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}\{1}", testName, String.IsNullOrEmpty(packageId) ? String.Empty : packageId)))
{
return testKey == null ? null : testKey.GetValue(state) as string;
}
}
private string ReadFeatureAction(string packageId, string featureId, string state)
{
string testName = this.Engine.GetVariableString("TestGroupName");
using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}\{1}", testName, packageId)))
{
string registryName = String.Concat(featureId, state);
return testKey == null ? null : testKey.GetValue(registryName) as string;
}
}
private string ReadTestRegistryValue(string name)
{
string testName = this.Engine.GetVariableString("TestGroupName");
using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\{0}\{1}", testName, name)))
{
return testKey == null ? null : testKey.GetValue("Version") as string;
}
}
private static bool TryParseEnum(string value, out T t)
{
try
{
t = (T)Enum.Parse(typeof(T), value, true);
return true;
}
catch (ArgumentException) { }
catch (OverflowException) { }
t = default(T);
return false;
}
}
}