Skip to content

Commit

Permalink
Replacing usages of LocalAppContextSwitches with `AppContextSwitchS…
Browse files Browse the repository at this point in the history
…cope` (#11539)

* Replacing usages of LocalAppContextSwitches with AppContextSwitchScopes

* Fix usings

* Refactoring to use named parameter and make AppContextSwitchNames use constants

* move files to better support TargetFrameworkName in AppContextSwitchScope

* More refactoring for LocalAppContextSwitchesTest

* Changes from review

* Remove try finally blocks

* Refactor tests based on feedback

* Fix test expected values

* change from review
  • Loading branch information
elachlan authored Jun 19, 2024
1 parent 9ac305f commit 5e1b5b5
Show file tree
Hide file tree
Showing 20 changed files with 394 additions and 200 deletions.
33 changes: 33 additions & 0 deletions src/Common/tests/TestUtilities/AnchorLayoutV2Scope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;

/// <summary>
/// Scope for enabling / disabling the AnchorLayoutV2 Switch.
/// Use in a <see langword="using"/> statement.
/// </summary>
public readonly ref struct AnchorLayoutV2Scope
{
private readonly AppContextSwitchScope _switchScope;

public AnchorLayoutV2Scope(bool enable)
{
// Prevent multiple AnchorLayoutV2Scope instances from running simultaneously.
// Using Monitor to allow recursion on the same thread.
Monitor.Enter(typeof(AnchorLayoutV2Scope));
_switchScope = new(AppContextSwitchNames.AnchorLayoutV2, enable);
}

public void Dispose()
{
try
{
_switchScope.Dispose();
}
finally
{
Monitor.Exit(typeof(AnchorLayoutV2Scope));
}
}
}
49 changes: 47 additions & 2 deletions src/Common/tests/TestUtilities/AppContextSwitchNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,60 @@ namespace System;

public static class AppContextSwitchNames
{
/// <summary>
/// The switch that controls whether AnchorLayoutV2 feature is enabled.
/// </summary>
public const string AnchorLayoutV2
= "System.Windows.Forms.AnchorLayoutV2";

/// <summary>
/// The switch that controls whether the parent font (as set by <see cref="Forms.Application.SetDefaultFont(Font)" />
/// or by the parent control or form's font) is applied to menus.
/// </summary>
public const string ApplyParentFontToMenus
= "System.Windows.Forms.ApplyParentFontToMenus";

/// <summary>
/// The switch that controls whether or not the DataGridView starts its UI row count at zero.
/// </summary>
public const string DataGridViewUIAStartRowCountAtZero
= "System.Windows.Forms.DataGridViewUIAStartRowCountAtZero";

/// <summary>
/// The switch that controls whether or not the <see cref="BinaryFormatter"/> is enabled.
/// </summary>
public static string EnableUnsafeBinaryFormatterSerialization { get; }
public const string EnableUnsafeBinaryFormatterSerialization
= "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization";

/// <summary>
/// Switch that controls <see cref="AppContext"/> switch caching.
/// </summary>
public static string LocalAppContext_DisableCaching { get; }
public const string LocalAppContext_DisableCaching
= "TestSwitch.LocalAppContext.DisableCaching";

/// <summary>
/// The switch that controls whether UIA notifications are raised.
/// </summary>
public const string NoClientNotifications
= "Switch.System.Windows.Forms.AccessibleObject.NoClientNotifications";

/// <summary>
/// The switch that controls whether to scale the top level form min/max size for dpi.
/// </summary>
public const string ScaleTopLevelFormMinMaxSizeForDpi
= "System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi";

/// <summary>
/// The switch that controls whether certificates are checked against the certificate authority revocation list.
/// If true, revoked certificates will not be accepted by WebRequests and WebClients as valid.
/// Otherwise, revoked certificates will be accepted as valid.
/// </summary>
public const string ServicePointManagerCheckCrl
= "System.Windows.Forms.ServicePointManagerCheckCrl";

/// <summary>
/// The switch that controls whether the TreeNodeCollection will insert nodes in the sorted order.
/// </summary>
public const string TreeNodeCollectionAddRangeRespectsSortOrder
= "System.Windows.Forms.ApplyParentFontToMenus";
}
33 changes: 33 additions & 0 deletions src/Common/tests/TestUtilities/ApplyParentFontToMenusScope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;

/// <summary>
/// Scope for enabling / disabling the ApplyParentFontToMenus Switch.
/// Use in a <see langword="using"/> statement.
/// </summary>
public readonly ref struct ApplyParentFontToMenusScope
{
private readonly AppContextSwitchScope _switchScope;

public ApplyParentFontToMenusScope(bool enable)
{
// Prevent multiple ApplyParentFontToMenusScopes from running simultaneously. Using Monitor to allow recursion on
// the same thread.
Monitor.Enter(typeof(ApplyParentFontToMenusScope));
_switchScope = new(AppContextSwitchNames.ApplyParentFontToMenus, enable);
}

public void Dispose()
{
try
{
_switchScope.Dispose();
}
finally
{
Monitor.Exit(typeof(ApplyParentFontToMenusScope));
}
}
}
2 changes: 1 addition & 1 deletion src/Common/tests/TestUtilities/BinaryFormatterScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public BinaryFormatterScope(bool enable)
// Prevent multiple BinaryFormatterScopes from running simultaneously. Using Monitor to allow recursion on
// the same thread.
Monitor.Enter(typeof(BinaryFormatterScope));
_switchScope = new AppContextSwitchScope(AppContextSwitchNames.EnableUnsafeBinaryFormatterSerialization, enable);
_switchScope = new(AppContextSwitchNames.EnableUnsafeBinaryFormatterSerialization, enable);
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;
/// <summary>
/// Scope for enabling / disabling the DataGridViewUIAStartRowCountAtZero Switch.
/// Use in a <see langword="using"/> statement.
/// </summary>
public readonly ref struct DataGridViewUIAStartRowCountAtZeroScope
{
private readonly AppContextSwitchScope _switchScope;

public DataGridViewUIAStartRowCountAtZeroScope(bool enable)
{
// Prevent multiple BinaryFormatterScopes from running simultaneously. Using Monitor to allow recursion on
// the same thread.
Monitor.Enter(typeof(DataGridViewUIAStartRowCountAtZeroScope));
_switchScope = new(AppContextSwitchNames.DataGridViewUIAStartRowCountAtZero, enable);
}

public void Dispose()
{
try
{
_switchScope.Dispose();
}
finally
{
Monitor.Exit(typeof(DataGridViewUIAStartRowCountAtZeroScope));
}
}
}
33 changes: 33 additions & 0 deletions src/Common/tests/TestUtilities/NoClientNotificationsScope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;

/// <summary>
/// Scope for enabling / disabling the NoClientNotifications Switch.
/// Use in a <see langword="using"/> statement.
/// </summary>
public readonly ref struct NoClientNotificationsScope
{
private readonly AppContextSwitchScope _switchScope;

public NoClientNotificationsScope(bool enable)
{
// Prevent multiple NoClientNotificationsScopes from running simultaneously. Using Monitor to allow recursion on
// the same thread.
Monitor.Enter(typeof(NoClientNotificationsScope));
_switchScope = new(AppContextSwitchNames.NoClientNotifications, enable);
}

public void Dispose()
{
try
{
_switchScope.Dispose();
}
finally
{
Monitor.Exit(typeof(NoClientNotificationsScope));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;

/// <summary>
/// Scope for enabling / disabling the ScaleTopLevelFormMinMaxSizeForDpi Switch.
/// Use in a <see langword="using"/> statement.
/// </summary>
public readonly ref struct ScaleTopLevelFormMinMaxSizeForDpiScope
{
private readonly AppContextSwitchScope _switchScope;

public ScaleTopLevelFormMinMaxSizeForDpiScope(bool enable)
{
// Prevent multiple ScaleTopLevelFormMinMaxSizeForDpi from running simultaneously.
// Using Monitor to allow recursion on the same thread.
Monitor.Enter(typeof(ScaleTopLevelFormMinMaxSizeForDpiScope));
_switchScope = new(AppContextSwitchNames.ScaleTopLevelFormMinMaxSizeForDpi, enable);
}

public void Dispose()
{
try
{
_switchScope.Dispose();
}
finally
{
Monitor.Exit(typeof(ScaleTopLevelFormMinMaxSizeForDpiScope));
}
}
}
33 changes: 33 additions & 0 deletions src/Common/tests/TestUtilities/ServicePointManagerCheckCrlScope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;

/// <summary>
/// Scope for enabling / disabling the ServicePointManagerCheckCrl Switch.
/// Use in a <see langword="using"/> statement.
/// </summary>
public readonly ref struct ServicePointManagerCheckCrlScope
{
private readonly AppContextSwitchScope _switchScope;

public ServicePointManagerCheckCrlScope(bool enable)
{
// Prevent multiple ServicePointManagerCheckCrlScope instances from running simultaneously.
// Using Monitor to allow recursion on the same thread.
Monitor.Enter(typeof(ServicePointManagerCheckCrlScope));
_switchScope = new(AppContextSwitchNames.ServicePointManagerCheckCrl, enable);
}

public void Dispose()
{
try
{
_switchScope.Dispose();
}
finally
{
Monitor.Exit(typeof(ServicePointManagerCheckCrlScope));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System;
/// <summary>
/// Scope for enabling / disabling the TreeNodeCollectionAddRangeRespectsSortOrder Switch.
/// Use in a <see langword="using"/> statement.
/// </summary>
public readonly ref struct TreeNodeCollectionAddRangeRespectsSortOrderScope
{
private readonly AppContextSwitchScope _switchScope;

public TreeNodeCollectionAddRangeRespectsSortOrderScope(bool enable)
{
// Prevent multiple TreeNodeCollectionAddRangeRespectsSortOrderScopes from running simultaneously. Using Monitor to allow recursion on
// the same thread.
Monitor.Enter(typeof(TreeNodeCollectionAddRangeRespectsSortOrderScope));
_switchScope = new(AppContextSwitchNames.TreeNodeCollectionAddRangeRespectsSortOrder, enable);
}

public void Dispose()
{
try
{
_switchScope.Dispose();
}
finally
{
Monitor.Exit(typeof(TreeNodeCollectionAddRangeRespectsSortOrderScope));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -218,33 +218,4 @@ public static bool TreeNodeCollectionAddRangeRespectsSortOrder
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => GetCachedSwitchValue(TreeNodeCollectionAddRangeRespectsSortOrderSwitchName, ref s_treeNodeCollectionAddRangeRespectsSortOrder);
}

internal static void SetLocalAppContextSwitchValue(string switchName, bool value)
{
if (switchName == NoClientNotificationsSwitchName)
{
s_noClientNotifications = value ? 1 : 0;
}

if (switchName == DataGridViewUIAStartRowCountAtZeroSwitchName)
{
s_dataGridViewUIAStartRowCountAtZero = value ? 1 : 0;
}

if (switchName == ApplyParentFontToMenusSwitchName)
{
s_applyParentFontToMenus = value ? 1 : 0;
}

if (switchName == TreeNodeCollectionAddRangeRespectsSortOrderSwitchName)
{
s_treeNodeCollectionAddRangeRespectsSortOrder = value ? 1 : 0;
}
}

internal static bool GetCachedSwitchValue(string switchName)
{
int cachedSwitchValue = 0;
return GetCachedSwitchValue(switchName, ref cachedSwitchValue);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.Versioning;
using System.Windows.Forms.Primitives;

namespace System;

#nullable enable

/// <summary>
/// Scope for setting the see <see cref="LocalAppContextSwitches.TargetFrameworkName" /> temporarily.
/// Use in a <see langword="using"/> statement.
/// </summary>
public readonly ref struct TargetFrameworkNameScope
{
private readonly FrameworkName? _previousTargetFrameworkName;
private readonly dynamic _testAccessor;

public TargetFrameworkNameScope(string targetFrameworkName)
{
_testAccessor = typeof(LocalAppContextSwitches).TestAccessor().Dynamic;
ResetLocalSwitches();
_previousTargetFrameworkName = LocalAppContextSwitches.TargetFrameworkName;
_testAccessor.s_targetFrameworkName = new FrameworkName(targetFrameworkName);
}

public void Dispose()
{
_testAccessor.s_targetFrameworkName = _previousTargetFrameworkName;
ResetLocalSwitches();
}

private void ResetLocalSwitches()
{
_testAccessor.s_anchorLayoutV2 = 0;
_testAccessor.s_scaleTopLevelFormMinMaxSizeForDpi = 0;
_testAccessor.s_trackBarModernRendering = 0;
_testAccessor.s_servicePointManagerCheckCrl = 0;
}
}
Loading

0 comments on commit 5e1b5b5

Please sign in to comment.