Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
b026c64
First verison
SiyuGithub Jan 6, 2023
d7718fa
Modify CocoaSynchronizationContextAdapter.cs pumptill method.
SiyuGithub Jan 10, 2023
9516e6d
Modify PumpTill.
SiyuGithub Jan 10, 2023
8fbeb9a
Modify more CocoaSynchronizationContext.cs and CocoaSynchronizationCo…
SiyuGithub Jan 10, 2023
e996a5c
Modify version2
SiyuGithub Jan 10, 2023
897247b
version3
SiyuGithub Jan 10, 2023
53bf326
Version4:
SiyuGithub Jan 10, 2023
fca1e86
Version5
SiyuGithub Jan 10, 2023
0d636e2
Version6
SiyuGithub Jan 11, 2023
68e2e49
CocoaFact code clean up
SiyuGithub Jan 17, 2023
04de106
More cleanup
SiyuGithub Jan 17, 2023
0bdc567
Use Mac app as harness for xunit test runner
sandyarmstrong Jan 18, 2023
2ca5096
Delete .DS_Store files
sandyarmstrong Jan 18, 2023
b621858
Ensure macos workload is installed
sandyarmstrong Jan 18, 2023
0695648
Convert to file-scoped namespaces
sandyarmstrong Jan 18, 2023
77e6854
Cleanup
sandyarmstrong Jan 18, 2023
a7cc92c
Address a few extraneous warnings
sandyarmstrong Jan 18, 2023
5727671
Only build Xunit.StaFact.Tests.Mac in *Mac configurations
sandyarmstrong Jan 18, 2023
3cf676c
Pass configuration when restoring on Mac
sandyarmstrong Jan 18, 2023
b13aa1d
Basic workload-from-rollback provisioning
sandyarmstrong Jan 18, 2023
153f2ec
Move Xunit.StaFact.Tests.Mac to .NET 6
sandyarmstrong Jan 18, 2023
cf8b3a6
Do not build for Mac on Linux
sandyarmstrong Jan 18, 2023
565faf6
Minor fixes
sandyarmstrong Jan 19, 2023
13063f2
Testing new added TargetPath
SiyuGithub Jan 19, 2023
c2531a3
Fix Mac files not showing up in VSMac solution pad
sandyarmstrong Jan 19, 2023
3d32350
Modify TargetPath more.
SiyuGithub Jan 20, 2023
d03833a
Make another change to test TargetPath
SiyuGithub Jan 20, 2023
3871190
Trying to get macos build working on Linux
sandyarmstrong Jan 20, 2023
715bbfc
Revert "Trying to get macos build working on Linux"
sandyarmstrong Jan 20, 2023
4eb7a71
Tests the CocoaFact unit tests in the DevOps Pipeline
SiyuGithub Jan 24, 2023
bdb092f
Replace TargetPath with another path
SiyuGithub Jan 24, 2023
f4f07b8
Testing
SiyuGithub Jan 24, 2023
f081705
Edit TargetPath
SiyuGithub Jan 24, 2023
d5f36c7
Change the TargetFramework for MacOS
SiyuGithub Jan 24, 2023
8110c72
.yml file clean up
SiyuGithub Jan 24, 2023
8a3a3b6
Another attempt for running CocoaFact unit tests
SiyuGithub Jan 24, 2023
8e75d0c
Another modification for the TargetPath
SiyuGithub Jan 24, 2023
30036b3
Fix Dotnet Test System.IO.FileNotFoundException
SiyuGithub Jan 24, 2023
696daac
Fix libhostpolicy.dylib is not found issue
SiyuGithub Jan 24, 2023
bb80ec5
Adding RuntimeIdentifier to solve libhostpolicy.dylib can't be found
SiyuGithub Jan 24, 2023
09fe7b4
Testing if the test can find libhostpolicy.dylib
SiyuGithub Jan 25, 2023
1de23a6
Replace RuntimeIdentifiers with RuntimeIdentifier
SiyuGithub Jan 25, 2023
643e8bf
Code clean up
SiyuGithub Jan 25, 2023
7c62d1b
Use RuntimeIdentifer instead of RuntimeIdentifiers
SiyuGithub Jan 25, 2023
676ed17
Testing the build pipeline for the new step
SiyuGithub Jan 26, 2023
9f0cb71
Testing pipeline test build
SiyuGithub Jan 26, 2023
90dae75
Test if the dotnet.yml stopped the pipeline run
SiyuGithub Jan 26, 2023
05460db
Modified dotnet.yml
SiyuGithub Jan 26, 2023
36b599c
Fixed AppDelegate.cs
SiyuGithub Jan 26, 2023
6dcf89f
Modify the Pipeline build steps
SiyuGithub Jan 26, 2023
30d506a
Create a powerShell script for Mac unit tests
SiyuGithub Jan 26, 2023
41570f8
Modify dotnet.yml
SiyuGithub Jan 27, 2023
2a198ad
Second solution, run script for Mac unit test in dotnet.yml
SiyuGithub Jan 27, 2023
67c4d92
XML test results generating locally
sandyarmstrong Jan 27, 2023
621aeb1
Modiy the dotnet.yml and add new task to publish the xml
SiyuGithub Jan 27, 2023
b99bc9a
Clean more code in dotnet.yml.
SiyuGithub Jan 27, 2023
aec7cf0
Add more changes
SiyuGithub Jan 27, 2023
2425934
test .yml version 1
SiyuGithub Jan 27, 2023
3c99e99
test .yml Version 2
SiyuGithub Jan 27, 2023
95c3b1f
Test .yml Version 3
SiyuGithub Jan 27, 2023
a44b4c6
Test .yml Version 4
SiyuGithub Jan 27, 2023
b832272
Test .yml Version 5
SiyuGithub Jan 27, 2023
e6db7d5
Test .yml Version 6
SiyuGithub Jan 27, 2023
37e2b59
Test .yml Version 7
SiyuGithub Jan 27, 2023
ef65384
Test .yml Version 8
SiyuGithub Jan 27, 2023
72516ac
Test .ml Version 9
SiyuGithub Jan 28, 2023
d9d14bc
Test .yml Version 10
SiyuGithub Jan 28, 2023
098c9f1
Test .yml Version 11
SiyuGithub Jan 28, 2023
3efebf8
Test .yml Version 12
SiyuGithub Jan 28, 2023
89a130d
Test .yml Version 13
SiyuGithub Jan 28, 2023
d028403
Test .yml Version 14
SiyuGithub Jan 28, 2023
b1a399d
Test .yml Version 15
SiyuGithub Jan 28, 2023
7cf2afb
Test .yml Version 16
SiyuGithub Jan 30, 2023
20e3476
Test .yml Version 17
SiyuGithub Jan 30, 2023
7f8b789
Test .yml Version 18
SiyuGithub Jan 30, 2023
7ae1504
Test .yml Version 19
SiyuGithub Jan 30, 2023
52180e4
Test .yml Version 21
SiyuGithub Jan 30, 2023
9dbf6be
Test .yml Version 22
SiyuGithub Jan 30, 2023
1b9a72d
Test .yml Version 23
SiyuGithub Jan 30, 2023
aaf5ead
Test .yml Version 24
SiyuGithub Jan 30, 2023
c6e76e7
Code clean up
SiyuGithub Jan 30, 2023
d69935f
More code testing
SiyuGithub Jan 30, 2023
1321b3c
More clean up
SiyuGithub Jan 30, 2023
b62abc3
Test pipeline V1
SiyuGithub Feb 1, 2023
892ca8b
Simplify the mac test project
AArnott Feb 6, 2023
bc5256d
Revert some sln file changes
AArnott Feb 6, 2023
8f61172
revert spacing change
AArnott Feb 6, 2023
4400fed
Cleanup pipeline
AArnott Feb 6, 2023
795fe77
fix pipeline
AArnott Feb 6, 2023
f9e66fc
Avoid double-build on mac
AArnott Feb 6, 2023
6a47cdd
Use checked in workloads.json file
AArnott Feb 6, 2023
c04316a
Add notes to CONTRIBUTING about requirement to run
AArnott Feb 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<TargetingWindows Condition=" '$(TargetFramework)' == 'net472' or $(TargetFramework.EndsWith('-windows')) ">true</TargetingWindows>
<TargetingMacos Condition=" '$(TargetFramework)' == 'net6.0-macos10.15' or $(TargetFramework.EndsWith('-macos')) ">true</TargetingMacos>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a contains syntax that may be better to use here if you're liable to use -macos10.15, so that the condition doesn't silently start failing when you later move to -macos12.
I think it's roughly this:
$(TargetFramework.Contains('macos'))


<!-- https://github.com/dotnet/msbuild/blob/main/documentation/ProjectReference-Protocol.md#setplatform-negotiation -->
<EnableDynamicPlatformResolution>true</EnableDynamicPlatformResolution>
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "7.0.101",
"version": "7.0.100",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume this is just to allow you to build locally on your box and not because 7.0.101 is broken somehow. We'll need to revert this before merging. You could do it now and upgrade your SDK to solve the problem if you want.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, this whole branch was just us getting far enough locally to have something we could mess with in the Mac editor project. It's definitely not cleaned up or complete yet. 😄

"rollForward": "patch",
"allowPrerelease": false
}
Expand Down
Binary file added src/.DS_Store
Binary file not shown.
Binary file added src/Xunit.StaFact/.DS_Store
Binary file not shown.
18 changes: 18 additions & 0 deletions src/Xunit.StaFact/Mac/CocoaFactAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE.txt file in the project root for full license information.
using System;
using System.Threading;
using Xunit.Sdk;

namespace Xunit
{
/// <summary>
/// Identifies an xunit test that starts on with a <see cref="System.Threading.SynchronizationContext"/>
/// running on <see cref="Foundation.NSRunLoop.Main"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Xunit.Sdk.CocoaFactDiscoverer", ThisAssembly.AssemblyName)]
public class CocoaFactAttribute : FactAttribute
{
}
}
18 changes: 18 additions & 0 deletions src/Xunit.StaFact/Mac/CocoaTheoryAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE.txt file in the project root for full license information.
using System;
using System.Threading;
using Xunit.Sdk;

namespace Xunit
{
/// <summary>
/// Identifies an xunit theory that starts on with a <see cref="System.Threading.SynchronizationContext"/>
/// running on <see cref="Foundation.NSRunLoop.Main"/>
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Xunit.Sdk.CocoaTheoryDiscoverer", ThisAssembly.AssemblyName)]
public class CocoaTheoryAttribute : TheoryAttribute
{
}
}
56 changes: 56 additions & 0 deletions src/Xunit.StaFact/Sdk.Mac/CocoaFactDiscoverer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE.txt file in the project root for full license information.

using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Xunit.Abstractions;

namespace Xunit.Sdk
{
/// <summary>
/// The discovery class for <see cref="CocoaFactDiscoverer"/>.
/// </summary>
public class CocoaFactDiscoverer : FactDiscoverer
{
private readonly IMessageSink diagnosticMessageSink;

/// <summary>
/// Initializes a new instance of the <see cref="CocoaFactDiscoverer"/> class.
/// </summary>
/// <param name="diagnosticMessageSink">The diagnostic message sink.</param>
public CocoaFactDiscoverer(IMessageSink diagnosticMessageSink)
: base(diagnosticMessageSink)
{
this.diagnosticMessageSink = diagnosticMessageSink;
}

class MyMessage: IMessageSinkMessage
{
public string Message { get; set; }
}

protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
{
var message = new MyMessage
{
Message = "Hello"
};

Console.WriteLine("hello!!");
diagnosticMessageSink.OnMessage(message);
if (testMethod.Method.ReturnType.Name == "System.Void" &&
testMethod.Method.GetCustomAttributes(typeof(AsyncStateMachineAttribute)).Any())
{
return new ExecutionErrorTestCase(this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod, "Async void methods are not supported.");
}

return (IXunitTestCase)new UITestCase(UITestCase.SyncContextType.Cocoa, this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod);

//return RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
// ? (IXunitTestCase)new UITestCase(UITestCase.SyncContextType.Cocoa, this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod)
// : new XunitSkippedDataRowTestCase(this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, "Cocoa only exists on macOS.");
}
}
}
198 changes: 198 additions & 0 deletions src/Xunit.StaFact/Sdk.Mac/CocoaSynchronizationContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// Copyright (c) Aaron Bockover. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE.txt file in the project root for full license information.

using System.Threading;

using Foundation;

namespace Xunit.Sdk
{
internal sealed class CocoaSynchronizationContext : SynchronizationContext
{

private readonly Queue<KeyValuePair<SendOrPostCallback, object?>> messageQueue = new Queue<KeyValuePair<SendOrPostCallback, object?>>();
private readonly int mainThread = Environment.CurrentManagedThreadId;
private readonly AsyncAutoResetEvent workItemDone = new AsyncAutoResetEvent();
private readonly string name;
private readonly bool shouldSetAsCurrent;
private int activeOperations;
private bool pumping;
private bool pumpingEnded;
private ExceptionAggregator? aggregator;

/// <summary>
/// Initializes a new instance of the <see cref="CocoaSynchronizationContext"/> class.
/// </summary>
public CocoaSynchronizationContext(string name, bool shouldSetAsCurrent)
{
this.name = name;
this.shouldSetAsCurrent = shouldSetAsCurrent;
}

internal bool IsInContext => this.mainThread == Environment.CurrentManagedThreadId;

private bool AnyMessagesInQueue
{
get
{
lock (this.messageQueue)
{
return this.messageQueue.Count > 0;
}
}
}

private bool AnyPendingOperations => Volatile.Read(ref this.activeOperations) > 0;

public override SynchronizationContext CreateCopy()
=> new CocoaSynchronizationContext(name, shouldSetAsCurrent);

public override void Post(SendOrPostCallback d, object state)
=> NSRunLoop.Main.BeginInvokeOnMainThread(() => d(state));

public override void Send(SendOrPostCallback d, object state)
=> NSRunLoop.Main.InvokeOnMainThread(() => d(state));

/// <summary>
/// Blocks the calling thread to pump messages until a task has completed.
/// </summary>
/// <param name="untilCompleted">The task that must complete to break out of the message loop.</param>
public void PumpMessages(Task untilCompleted)
{
this.VerifyState();

this.pumping = true;
try
{
// Arrange to wake up immediately when the task completes.
untilCompleted.ContinueWith(
_ =>
{
lock (this.messageQueue)
{
Monitor.Pulse(this.messageQueue);
}
},
TaskScheduler.Default);

// Now run the message loop until the task completes.
while (!untilCompleted.IsCompleted)
{
this.TryOneWorkItem();
}
}
finally
{
this.pumping = false;
this.pumpingEnded = true;
}
}

public async Task WaitForOperationCompletionAsync()
{
while (this.AnyPendingOperations || this.AnyMessagesInQueue)
{
await this.workItemDone.WaitAsync().ConfigureAwait(false);
}
}

/// <summary>
/// Pump messages until all pending operations have completed
/// and the message queue is empty.
/// </summary>
public void CompleteOperations()
{
this.VerifyState();
this.pumping = true;
try
{
while (this.AnyPendingOperations || this.AnyMessagesInQueue)
{
this.TryOneWorkItem();
}
}
finally
{
this.pumping = false;
}
}

/// <inheritdoc />
public override void OperationStarted()
{
Interlocked.Increment(ref this.activeOperations);
}

/// <inheritdoc />
public override void OperationCompleted()
{
int result = Interlocked.Decrement(ref this.activeOperations);
if (result == 0)
{
// Give any message waiter a heads up that the operation count has reached zero,
// in case the queue is empty at the same time the operation count is, which
// is usually a sign to return to its caller.
lock (this.messageQueue)
{
Monitor.Pulse(this.messageQueue);
}
}
}

internal void SetExceptionAggregator(ExceptionAggregator aggregator)
{
this.aggregator = aggregator;
}

private void VerifyState()
{
if (Environment.CurrentManagedThreadId != this.mainThread)
{
throw new InvalidOperationException("Wrong thread");
}

if (Current != this && this.shouldSetAsCurrent)
{
throw new InvalidOperationException("Wrong sync context");
}

if (this.pumping)
{
throw new InvalidOperationException("Already pumping");
}
}

private bool TryOneWorkItem()
{
KeyValuePair<SendOrPostCallback, object?> work = default;
lock (this.messageQueue)
{
if (this.messageQueue.Count == 0)
{
Monitor.Wait(this.messageQueue);
return false;
}

work = this.messageQueue.Dequeue();
}

try
{
if (this.aggregator is object)
{
this.aggregator.Run(() => work.Key(work.Value));
}
else
{
work.Key(work.Value);
}

return true;
}
finally
{
this.workItemDone.Set();
}
}
}
}
35 changes: 35 additions & 0 deletions src/Xunit.StaFact/Sdk.Mac/CocoaSynchronizationContextAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Aaron Bockover. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE.txt file in the project root for full license information.

using System;
using System.Threading;
using System.Threading.Tasks;

using Foundation;

namespace Xunit.Sdk
{
internal class CocoaSynchronizationContextAdapter : SyncContextAdapter
{
internal static readonly SyncContextAdapter Default = new CocoaSynchronizationContextAdapter();

private CocoaSynchronizationContextAdapter()
{
}

internal override bool CanCompleteOperations => true;

internal override SynchronizationContext Create(string name) => new CocoaSynchronizationContext(name, this.ShouldSetAsCurrent);

internal override Task WaitForOperationCompletionAsync(SynchronizationContext syncContext) => ((CocoaSynchronizationContext)syncContext).WaitForOperationCompletionAsync();

// internal override void CompleteOperations()
// {
// }

internal override void PumpTill(SynchronizationContext synchronizationContext, Task task)
{
((CocoaSynchronizationContext)synchronizationContext).PumpMessages(task);
}
}
}
40 changes: 40 additions & 0 deletions src/Xunit.StaFact/Sdk.Mac/CocoaTheoryDiscoverer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE.txt file in the project root for full license information.

using System.Collections.Generic;
using System.Runtime.InteropServices;
using Xunit.Abstractions;

namespace Xunit.Sdk
{
/// <summary>
/// The discovery class for <see cref="CocoaTheoryAttribute"/>.
/// </summary>
public class CocoaTheoryDiscoverer : TheoryDiscoverer
{
/// <summary>
/// Initializes a new instance of the <see cref="CocoaTheoryDiscoverer"/> class.
/// </summary>
/// <param name="diagnosticMessageSink">The diagnostic message sink.</param>
public CocoaTheoryDiscoverer(IMessageSink diagnosticMessageSink)
: base(diagnosticMessageSink)
{
}

protected override IEnumerable<IXunitTestCase> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow)
{
yield return (IXunitTestCase)new UITestCase(UITestCase.SyncContextType.Cocoa, this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, dataRow);
//yield return RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
// ? (IXunitTestCase)new UITestCase(UITestCase.SyncContextType.Cocoa, this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, dataRow)
// : new XunitSkippedDataRowTestCase(this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, "Cocoa only exists on macOS.");
}

protected override IEnumerable<IXunitTestCase> CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute)
{
yield return (IXunitTestCase)new UITheoryTestCase(UITestCase.SyncContextType.Cocoa, this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod);
//yield return RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
// ? (IXunitTestCase)new UITheoryTestCase(UITestCase.SyncContextType.Cocoa, this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod)
// : new XunitSkippedDataRowTestCase(this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, "Cocoa only exists on macOS.");
}
}
}
Loading