Skip to content

Commit

Permalink
Merge branch 'master' into MigrateXunit3
Browse files Browse the repository at this point in the history
  • Loading branch information
jbe2277 committed Jan 26, 2025
2 parents 383e1db + f73dbf0 commit 5ad7247
Show file tree
Hide file tree
Showing 17 changed files with 100 additions and 70 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2016-2023 jbe2277
Copyright (c) 2016-2025 jbe2277

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion src/NewsReader/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<MauiVersion>9.0.21</MauiVersion>
<MauiVersion>9.0.22</MauiVersion>

<NeutralLanguage>en</NeutralLanguage>
<Nullable>enable</Nullable>
Expand Down
18 changes: 9 additions & 9 deletions src/NewsReader/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

<ItemGroup>
<!-- Build -->
<!-- Build -->
<PackageVersion Include="MinVer" Version="6.0.0" />

<!-- App -->
<PackageVersion Include="Autofac" Version="8.2.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageVersion Include="NLog" Version="5.3.4" />
<PackageVersion Include="Microsoft.Graph" Version="5.67.0" />
<PackageVersion Include="Microsoft.Identity.Client" Version="4.66.2" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.66.2" />
<PackageVersion Include="System.ServiceModel.Syndication" Version="9.0.0" />
<PackageVersion Include="System.Waf.Core" Version="8.0.1" />
<PackageVersion Include="Microsoft.Graph" Version="5.68.0" />
<PackageVersion Include="Microsoft.Identity.Client.Broker" Version="4.67.2" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.67.2" />
<PackageVersion Include="System.ServiceModel.Syndication" Version="9.0.1" />
<PackageVersion Include="System.Waf.Core" Version="8.0.2-alpha.0.81" />

<!-- Unit tests -->
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="xunit.v3" Version="1.0.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.0" />
<PackageVersion Include="System.Waf.UnitTesting.Core" Version="8.0.1" />
<PackageVersion Include="System.Waf.UnitTesting.Core" Version="8.0.2-alpha.0.81" />
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions src/NewsReader/NewsReader.Presentation/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public App(ISettingsService settingsService, IAppInfoService appInfoService, Laz

public static string LogFileName { get; } = Path.Combine(FileSystem.CacheDirectory, "Logging", "AppLog.txt");

public static Window? CurrentWindow { get; private set; }

protected override Window CreateWindow(IActivationState? activationState)
{
var window = new Window((Page)appController.MainView)
Expand All @@ -56,6 +58,7 @@ protected override Window CreateWindow(IActivationState? activationState)
window.Stopped += (_, _) => OnStopped();
window.Destroying += (_, _) => OnDestroying();
window.Resumed += (_, _) => OnResumed();
CurrentWindow = window;
return window;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<PackageReference Include="Microsoft.Maui.Controls" VersionOverride="$(MauiVersion)" />

<PackageReference Include="Microsoft.Graph" />
<PackageReference Include="Microsoft.Identity.Client" />
<PackageReference Include="Microsoft.Identity.Client.Broker" />
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" />
<PackageReference Include="System.ServiceModel.Syndication" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Microsoft.Graph.Models;
using Microsoft.Graph.Models.ODataErrors;
using Microsoft.Identity.Client;
using Microsoft.Identity.Client.Extensions.Msal;
using Microsoft.Kiota.Abstractions.Authentication;
using Waf.NewsReader.Applications.Services;

Expand Down Expand Up @@ -41,6 +40,12 @@ public WebStorageService()
builder.WithParentActivityOrWindow(() => Platform.CurrentActivity);
#elif IOS
builder.WithIosKeychainSecurityGroup(Foundation.NSBundle.MainBundle.BundleIdentifier);
#elif WINDOWS
Microsoft.Identity.Client.Broker.BrokerExtension.WithBroker(builder, new BrokerOptions(BrokerOptions.OperatingSystems.Windows)
{
Title = AppInfo.Name
});
builder.WithParentActivityOrWindow(() => WinRT.Interop.WindowNative.GetWindowHandle(App.CurrentWindow!.Handler.PlatformView!));
#endif
publicClient = builder.Build();
}
Expand All @@ -61,8 +66,8 @@ public async Task<bool> TrySilentSignIn()
if (!cacheInitialized && publicClient is not null)
{
cacheInitialized = true;
var storageProperties = new StorageCreationPropertiesBuilder("msal.dat", FileSystem.CacheDirectory).Build();
var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties);
var storageProperties = new Microsoft.Identity.Client.Extensions.Msal.StorageCreationPropertiesBuilder("msal.dat", FileSystem.CacheDirectory).Build();
var cacheHelper = await Microsoft.Identity.Client.Extensions.Msal.MsalCacheHelper.CreateAsync(storageProperties);
cacheHelper.RegisterCache(publicClient.UserTokenCache);
}
#endif
Expand Down Expand Up @@ -180,11 +185,14 @@ private async Task InitGraphClient()
private async Task<CustomDriveItemItemRequestBuilder> GetItemRequest(string fileName)
{
if (graphClient is null) throw new InvalidOperationException("graphClient is null");
var driveItem = await graphClient.Me.Drive.GetAsync().ConfigureAwait(false);
ArgumentNullException.ThrowIfNull(driveItem);
var appRootFolder = await graphClient.Drives[driveItem.Id].Special["AppRoot"].GetAsync().ConfigureAwait(false);
ArgumentNullException.ThrowIfNull(appRootFolder);
return graphClient.Drives[driveItem.Id].Items[appRootFolder.Id].ItemWithPath(fileName);

// Using workaround to get the driveId because AppFolder scope does not allow to the read Drive directly. https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/2624
var result = await graphClient.Me.Drive.WithUrl($"{graphClient.RequestAdapter.BaseUrl}/drive/special/approot:/{fileName}").GetAsync().ConfigureAwait(false);
var driveId = result?.Id?.Split("!")[0] ?? throw new InvalidOperationException("graphClient: not able to get the driveId");

var appRootFolder = await graphClient.Drives[driveId].Special["AppRoot"].GetAsync().ConfigureAwait(false)
?? throw new InvalidOperationException("graphClient: not able to get the appRootFolder");
return graphClient.Drives[driveId].Items[appRootFolder.Id].ItemWithPath(fileName);
}

static partial void GetApplicationId(ref string? applicationId);
Expand Down
2 changes: 1 addition & 1 deletion src/System.Waf/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<Company>jbe2277</Company>
<Copyright>Copyright © 2016-2024 jbe2277</Copyright>
<Copyright>Copyright © 2016-2025 jbe2277</Copyright>
<NeutralLanguage>en-US</NeutralLanguage>
<Nullable>enable</Nullable>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
Expand Down
4 changes: 2 additions & 2 deletions src/System.Waf/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<!-- Unit tests -->
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="MSTest.TestAdapter" Version="3.7.0" />
<PackageVersion Include="MSTest.TestFramework" Version="3.7.0" />
<PackageVersion Include="MSTest.TestAdapter" Version="3.6.4" />
<PackageVersion Include="MSTest.TestFramework" Version="3.6.4" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Waf.Foundation;
using System.Waf.UnitTesting;

namespace Test.Waf.Foundation
{
Expand All @@ -16,6 +18,23 @@ public async Task RunTest()
Assert.AreEqual(42, result);
}

[TestMethod]
public void RunWithCancellationTest()
{
using var context = UnitTestSynchronizationContext.Create();

var task = TaskHelper.Run(() => 42, TaskScheduler.FromCurrentSynchronizationContext());
var result = task.GetResult(context);
Assert.AreEqual(42, result);

bool called = false;
var cts = new CancellationTokenSource();
var task2 = TaskHelper.Run(() => called = true, TaskScheduler.FromCurrentSynchronizationContext(), cts.Token);
cts.Cancel();
AssertHelper.ExpectedException<TaskCanceledException>(() => task2.Wait(context));
Assert.IsFalse(called);
}

[TestMethod]
public async Task NoWaitTest()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void InvokeMaxEveryDelayTimeTestWithSynchronizationContext()
public void InvokeOnlyIfIdleForDelayTimePerformanceTest()
{
int actionCallCount = 0;
var throttledAction = new ThrottledAction(() => Interlocked.Add(ref actionCallCount, 1), ThrottledActionMode.InvokeOnlyIfIdleForDelayTime, TimeSpan.FromMilliseconds(10));
var throttledAction = new ThrottledAction(() => Interlocked.Add(ref actionCallCount, 1), ThrottledActionMode.InvokeOnlyIfIdleForDelayTime, TimeSpan.FromMilliseconds(20));
for (int i = 0; i < 200000; i++)
{
throttledAction.InvokeAccumulated();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ public void ValidationResultComparerTest()
var comparerType = typeof(ValidatableModel).GetNestedType("ValidationResultComparer", BindingFlags.NonPublic)!;
var comparer = (IEqualityComparer<ValidationResult>)comparerType.GetProperty("Default", BindingFlags.Static | BindingFlags.Public)!.GetValue(null)!;

Assert.IsTrue(comparer.Equals(null, null));
Assert.IsFalse(comparer.Equals(new ValidationResult(null), null));
Assert.IsFalse(comparer.Equals(null, new ValidationResult(null)));
Assert.IsTrue(comparer.Equals(null!, null!));
Assert.IsFalse(comparer.Equals(new ValidationResult(null), null!));
Assert.IsFalse(comparer.Equals(null!, new ValidationResult(null)));
Assert.IsTrue(comparer.Equals(new ValidationResult(null), new ValidationResult(null)));
Assert.IsFalse(comparer.Equals(new ValidationResult("Test"), new ValidationResult("Bill")));
Assert.IsTrue(comparer.Equals(new ValidationResult("Test"), new ValidationResult("Test")));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net8.0</TargetFrameworks>
<TargetFrameworks>net48;net8.0</TargetFrameworks>
<RootNamespace>Test.Waf</RootNamespace>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>
Expand All @@ -12,8 +12,4 @@
<ItemGroup>
<ProjectReference Include="..\System.Waf.UnitTesting.Core\System.Waf.UnitTesting.Core.csproj" />
</ItemGroup>

<PropertyGroup Condition="$(TargetFramework.StartsWith(net4))">
<NoWarn>$(NoWarn);8625</NoWarn>
</PropertyGroup>
</Project>
25 changes: 23 additions & 2 deletions src/System.Waf/System.Waf/System.Waf.Core/Foundation/TaskHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static class TaskHelper
/// <returns>A task that represents the work queued to execute in the ThreadPool.</returns>
public static Task Run(Action action, TaskScheduler scheduler)
{
return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, scheduler);
return Run(action, scheduler, CancellationToken.None);
}

/// <summary>Queues the specified work to run on the thread pool and returns a proxy for the task returned by function.</summary>
Expand All @@ -22,7 +22,28 @@ public static Task Run(Action action, TaskScheduler scheduler)
/// <returns>A task that represents the work queued to execute in the ThreadPool.</returns>
public static Task<T> Run<T>(Func<T> action, TaskScheduler scheduler)
{
return Task<T>.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, scheduler);
return Run(action, scheduler, CancellationToken.None);
}

/// <summary>Queues the specified work to run on the thread pool and returns a Task object that represents that work.</summary>
/// <param name="action">The work to execute asynchronously</param>
/// <param name="scheduler">The TaskScheduler that is used to schedule the created Task.</param>
/// <param name="cancellation">The cancellation token that will be assigned to the new task.</param>
/// <returns>A task that represents the work queued to execute in the ThreadPool.</returns>
public static Task Run(Action action, TaskScheduler scheduler, CancellationToken cancellation)
{
return Task.Factory.StartNew(action, cancellation, TaskCreationOptions.DenyChildAttach, scheduler);
}

/// <summary>Queues the specified work to run on the thread pool and returns a proxy for the task returned by function.</summary>
/// <typeparam name="T">The type of the result produced by this task.</typeparam>
/// <param name="action">The work to execute asynchronously</param>
/// <param name="scheduler">The TaskScheduler that is used to schedule the created Task.</param>
/// <param name="cancellation">The cancellation token that will be assigned to the new task.</param>
/// <returns>A task that represents the work queued to execute in the ThreadPool.</returns>
public static Task<T> Run<T>(Func<T> action, TaskScheduler scheduler, CancellationToken cancellation)
{
return Task<T>.Factory.StartNew(action, cancellation, TaskCreationOptions.DenyChildAttach, scheduler);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public enum ThrottledActionMode
public class ThrottledAction
{
private readonly TaskScheduler taskScheduler;
private readonly object cancellationTokenSourceLock = new object();
private readonly Action action;
private readonly ThrottledActionMode mode;
private readonly TimeSpan delayTime;
Expand All @@ -44,50 +43,42 @@ public ThrottledAction(Action action)
/// <exception cref="ArgumentNullException">The argument action must not be null.</exception>
public ThrottledAction(Action action, ThrottledActionMode mode, TimeSpan delayTime)
{
taskScheduler = SynchronizationContext.Current != null ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Default;
taskScheduler = SynchronizationContext.Current is not null ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Default;
this.action = action ?? throw new ArgumentNullException(nameof(action));
this.mode = mode;
this.delayTime = delayTime;
}

/// <summary>Indicates that an execution of the action delegate is requested.</summary>
public bool IsRunning => cancellationTokenSource != null;
public bool IsRunning => cancellationTokenSource is not null;

/// <summary>Requests the execution of the action delegate.</summary>
public void InvokeAccumulated()
{
CancellationToken? token = null;
lock (cancellationTokenSourceLock)
{
if (mode == ThrottledActionMode.InvokeOnlyIfIdleForDelayTime || cancellationTokenSource == null)
{
cancellationTokenSource?.Cancel();
cancellationTokenSource = new CancellationTokenSource();
token = cancellationTokenSource.Token;
}
}
if (mode is not ThrottledActionMode.InvokeOnlyIfIdleForDelayTime && cancellationTokenSource is not null) return;

if (token != null)
var cts = new CancellationTokenSource();
if (mode is ThrottledActionMode.InvokeOnlyIfIdleForDelayTime)
{
Interlocked.Exchange(ref cancellationTokenSource, cts)?.Cancel();
}
else // mode is InvokeMaxEveryDelayTime
{
Task.Delay(delayTime, token.Value).ContinueWith(t =>
{
lock (cancellationTokenSourceLock)
{
cancellationTokenSource = null;
}
TaskHelper.Run(action, taskScheduler);
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
var old = Interlocked.CompareExchange(ref cancellationTokenSource, cts, null);
if (old is not null) return;
}

Task.Delay(delayTime, cts.Token).ContinueWith(t =>
{
Interlocked.Exchange(ref cancellationTokenSource, null);
TaskHelper.Run(action, taskScheduler);
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
}

/// <summary>Cancel the execution of the action delegate that was requested.</summary>
public void Cancel()
{
lock (cancellationTokenSourceLock)
{
cancellationTokenSource?.Cancel();
cancellationTokenSource = null;
}
Interlocked.Exchange(ref cancellationTokenSource, null)?.Cancel();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
<Description>System.Waf is a lightweight framework that helps you to create well-structured XAML applications. This core package can be used in various application types.</Description>
</PropertyGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith(net4))">
<Reference Include="System.ComponentModel.DataAnnotations" />
</ItemGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith(netstandard))">
<PackageReference Include="System.ComponentModel.Annotations" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
<Description>System.Waf is a lightweight framework that helps you to create well-structured XAML applications. This package supports writing unit tests. It can be used in various application types.</Description>
</PropertyGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith(net4))">
<Reference Include="System.ComponentModel.DataAnnotations" />
</ItemGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith(netstandard))">
<PackageReference Include="System.ComponentModel.Annotations" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net8.0-windows</TargetFrameworks>
<TargetFrameworks>net48;net8.0-windows</TargetFrameworks>
<RootNamespace>Test.Waf</RootNamespace>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<UseWPF>true</UseWPF>
Expand Down

0 comments on commit 5ad7247

Please sign in to comment.