-
Notifications
You must be signed in to change notification settings - Fork 406
Break circular dependency: remove Test.Common reference from Lab.Api #5896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
58 changes: 58 additions & 0 deletions
58
src/client/Microsoft.Identity.Lab.Api/Helpers/AppAccessorWithPartitionAsserts.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using Microsoft.Identity.Client; | ||
| using Microsoft.Identity.Client.Cache.Items; | ||
| using Microsoft.Identity.Client.Core; | ||
| using Microsoft.Identity.Client.PlatformsCommon.Shared; | ||
| using Microsoft.Identity.Lab.Api.Helpers; | ||
|
|
||
| namespace Microsoft.Identity.Lab.Api.Helpers | ||
| { | ||
| internal class AppAccessorWithPartitionAsserts : InMemoryPartitionedAppTokenCacheAccessor | ||
| { | ||
| public AppAccessorWithPartitionAsserts( | ||
| ILoggerAdapter logger, | ||
| CacheOptions tokenCacheAccessorOptions) : base(logger, tokenCacheAccessorOptions) | ||
| { | ||
|
|
||
| } | ||
|
|
||
| public override List<MsalAccessTokenCacheItem> GetAllAccessTokens(string partitionKey = null, ILoggerAdapter requestlogger = null) | ||
| { | ||
| Assert.IsNotNull(partitionKey); | ||
| return base.GetAllAccessTokens(partitionKey, requestlogger); | ||
| } | ||
|
|
||
| public override List<MsalAccountCacheItem> GetAllAccounts(string partitionKey = null, ILoggerAdapter requestlogger = null) | ||
| { | ||
| Assert.IsNotNull(partitionKey); | ||
| Assert.Fail("App token cache - do not call GetAllAccounts"); | ||
| throw new InvalidOperationException(); | ||
| } | ||
|
|
||
| public override List<MsalIdTokenCacheItem> GetAllIdTokens(string partitionKey = null, ILoggerAdapter requestlogger = null) | ||
| { | ||
| Assert.IsNotNull(partitionKey); | ||
|
|
||
| Assert.Fail("App token cache - do not call GetAllIdTokens"); | ||
| throw new InvalidOperationException(); | ||
| } | ||
|
|
||
| public override List<MsalRefreshTokenCacheItem> GetAllRefreshTokens(string partitionKey = null, ILoggerAdapter requestlogger = null) | ||
| { | ||
| Assert.IsNotNull(partitionKey); | ||
|
|
||
| Assert.Fail("App token cache - do not call GetAllRefreshTokens"); | ||
| throw new InvalidOperationException(); | ||
| } | ||
|
|
||
| public override bool HasAccessOrRefreshTokens() | ||
| { | ||
| Assert.Fail("HasAccessOrRefreshTokens was called. It should not be called unless the token cache serialization hooks"); | ||
| throw new InvalidOperationException(); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
|
|
||
| namespace Microsoft.Identity.Lab.Api.Helpers | ||
| { | ||
| /// <summary> | ||
| /// Lightweight assertion helper that throws <see cref="InvalidOperationException"/> | ||
| /// instead of depending on MSTest. Intended for use in mock infrastructure only. | ||
| /// </summary> | ||
| internal static class Assert | ||
| { | ||
| public static void AreEqual<T>(T expected, T actual, string message = null) | ||
| { | ||
| if (!EqualityComparer<T>.Default.Equals(expected, actual)) | ||
| { | ||
| throw new InvalidOperationException( | ||
| message ?? $"Assert.AreEqual failed. Expected: <{expected}>. Actual: <{actual}>."); | ||
| } | ||
| } | ||
|
|
||
| public static void IsTrue(bool condition, string message = null) | ||
| { | ||
| if (!condition) | ||
| { | ||
| throw new InvalidOperationException( | ||
| message ?? "Assert.IsTrue failed."); | ||
| } | ||
| } | ||
|
|
||
| public static void IsFalse(bool condition, string message = null) | ||
| { | ||
| if (condition) | ||
| { | ||
| throw new InvalidOperationException( | ||
| message ?? "Assert.IsFalse failed."); | ||
| } | ||
| } | ||
|
|
||
| public static void IsNotNull(object value, string message = null) | ||
| { | ||
| if (value == null) | ||
| { | ||
| throw new InvalidOperationException( | ||
| message ?? "Assert.IsNotNull failed."); | ||
| } | ||
| } | ||
|
|
||
| public static void IsEmpty<T>(ICollection<T> collection, string message = null) | ||
| { | ||
| if (collection != null && collection.Count > 0) | ||
| { | ||
| throw new InvalidOperationException( | ||
| message ?? $"Assert.IsEmpty failed. Collection has {collection.Count} element(s)."); | ||
| } | ||
| } | ||
|
|
||
| public static void IsEmpty<T>(IEnumerable<T> collection, string message = null) | ||
| { | ||
| if (collection != null && collection.Any()) | ||
| { | ||
| throw new InvalidOperationException( | ||
|
gladjohn marked this conversation as resolved.
|
||
| message ?? "Assert.IsEmpty failed. Collection is not empty."); | ||
| } | ||
| } | ||
|
|
||
| public static void HasCount<T>(int expectedCount, ICollection<T> collection, string message = null) | ||
| { | ||
| int actual = collection?.Count ?? 0; | ||
| if (actual != expectedCount) | ||
| { | ||
| throw new InvalidOperationException( | ||
| message ?? $"Assert.HasCount failed. Expected: {expectedCount}. Actual: {actual}."); | ||
| } | ||
| } | ||
|
gladjohn marked this conversation as resolved.
|
||
|
|
||
| public static void Contains<T>(T item, ICollection<T> collection, string message = null) | ||
| { | ||
| if (collection == null || !collection.Contains(item)) | ||
| { | ||
| throw new InvalidOperationException( | ||
| message ?? $"Assert.Contains failed. Item <{item}> not found in collection."); | ||
| } | ||
| } | ||
|
|
||
| public static void Fail(string message) | ||
| { | ||
| throw new InvalidOperationException(message ?? "Assert.Fail was called."); | ||
| } | ||
| } | ||
| } | ||
142 changes: 142 additions & 0 deletions
142
src/client/Microsoft.Identity.Lab.Api/Helpers/CoreAssert.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Reflection; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using Microsoft.Identity.Client; | ||
| using Microsoft.Identity.Client.Utils; | ||
| using Microsoft.Identity.Lab.Api.Helpers; | ||
|
|
||
| namespace Microsoft.Identity.Lab.Api.Helpers | ||
| { | ||
| /// <summary> | ||
| /// Provides custom assertion helpers for MSAL.NET test scenarios. | ||
| /// </summary> | ||
| internal static class CoreAssert | ||
| { | ||
| /// <summary> | ||
| /// Asserts that two scope strings represent the same set of scopes. | ||
| /// </summary> | ||
| public static void AreScopesEqual(string scopesExpected, string scopesActual) | ||
| { | ||
| var expectedScopes = ScopeHelper.ConvertStringToScopeSet(scopesExpected); | ||
| var actualScopes = ScopeHelper.ConvertStringToScopeSet(scopesActual); | ||
|
|
||
| Assert.HasCount(expectedScopes.Count, actualScopes); | ||
| foreach (string expectedScope in expectedScopes) | ||
| { | ||
| Assert.Contains(expectedScope, actualScopes); | ||
| } | ||
| } | ||
|
|
||
| internal static void AreAccountsEqual( | ||
| string expectedUsername, | ||
| string expectedEnv, | ||
| string expectedId, | ||
| string expectedTid, | ||
| string expectedOid, | ||
| params IAccount[] accounts) | ||
| { | ||
| foreach (var account in accounts) | ||
| { | ||
| Assert.AreEqual(expectedUsername, account.Username); | ||
| Assert.AreEqual(expectedEnv, account.Environment); | ||
| Assert.AreEqual(expectedId, account.HomeAccountId.Identifier); | ||
| Assert.AreEqual(expectedTid, account.HomeAccountId.TenantId); | ||
| Assert.AreEqual(expectedOid, account.HomeAccountId.ObjectId); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Asserts that three values are all equal to each other. | ||
| /// </summary> | ||
| public static void AreEqual<T>(T val1, T val2, T val3) | ||
| { | ||
| Assert.AreEqual(val1, val2, "First and second values differ"); | ||
| Assert.AreEqual(val1, val3, "First and third values differ"); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Asserts that two <see cref="DateTimeOffset"/> values are within one second of each other. | ||
| /// </summary> | ||
| public static void AreWithinOneSecond(DateTimeOffset expected, DateTimeOffset actual, string message = "") | ||
| { | ||
| IsWithinRange(expected, actual, TimeSpan.FromSeconds(1), message); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Asserts that two <see cref="DateTimeOffset"/> values are within a specified range of each other. | ||
| /// </summary> | ||
| public static void IsWithinRange(DateTimeOffset expected, DateTimeOffset actual, TimeSpan range, string message = "") | ||
| { | ||
| TimeSpan t = expected - actual; | ||
| Assert.IsTrue(t >= -range && t <= range, | ||
| $"{message} The dates are off by {t.TotalMilliseconds}ms, which is more than the expected {range.TotalMilliseconds}ms"); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Asserts that two dictionaries are equal. | ||
| /// </summary> | ||
| public static void AssertDictionariesAreEqual<TKey, TValue>( | ||
| IDictionary<TKey, TValue> dict1, | ||
| IDictionary<TKey, TValue> dict2, | ||
| IEqualityComparer<TValue> valueComparer) | ||
| { | ||
| Assert.IsTrue(DictionariesAreEqual(dict1, dict2, valueComparer)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Asserts that the specified type is immutable. | ||
| /// </summary> | ||
| public static void IsImmutable<T>() | ||
| { | ||
| Assert.IsTrue(IsImmutable(typeof(T))); | ||
| } | ||
|
|
||
| private static bool IsImmutable(Type type) | ||
| { | ||
| if (type == typeof(string) || type.IsPrimitive || type.IsEnum) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| #pragma warning disable IL2070, IL2067 | ||
| var fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | ||
| #pragma warning restore IL2070, IL2067 | ||
| var isShallowImmutable = fieldInfos.All(f => f.IsInitOnly); | ||
|
|
||
| if (!isShallowImmutable) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| return fieldInfos.All(f => IsImmutable(f.FieldType)); | ||
| } | ||
|
|
||
| private static bool DictionariesAreEqual<TKey, TValue>( | ||
| IDictionary<TKey, TValue> dict1, | ||
| IDictionary<TKey, TValue> dict2, | ||
| IEqualityComparer<TValue> valueComparer) | ||
| { | ||
| if (dict1 == dict2) | ||
| return true; | ||
| if ((dict1 == null) || (dict2 == null)) | ||
| return false; | ||
| if (dict1.Count != dict2.Count) | ||
| return false; | ||
|
|
||
| foreach (var kvp in dict1) | ||
| { | ||
| if (!dict2.TryGetValue(kvp.Key, out TValue value2)) | ||
| return false; | ||
| if (!valueComparer.Equals(kvp.Value, value2)) | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.