Added new feature : display the file/folder and link of a SharingLink object in the permissions reports.

This commit is contained in:
Dev
2026-05-12 15:20:51 +02:00
parent ecc7b329d4
commit 1312dcdb1e
26 changed files with 937 additions and 82 deletions
@@ -3,7 +3,8 @@ using SharepointToolbox.Core.Helpers;
namespace SharepointToolbox.Tests.Services;
/// <summary>
/// Tests for PERM-03: external user detection and permission-level filtering.
/// Tests for PERM-03: external user detection, permission-level filtering,
/// and SharePoint system-group classification (Limited Access / SharingLinks).
/// Pure static logic — runs immediately without stubs.
/// </summary>
public class PermissionEntryClassificationTests
@@ -13,7 +14,6 @@ public class PermissionEntryClassificationTests
[Fact]
public void IsExternalUser_WithExtHashInLoginName_ReturnsTrue()
{
// B2B guest login names contain the literal "#EXT#" fragment
Assert.True(PermissionEntryHelper.IsExternalUser("ext_user_domain.com#EXT#@contoso.onmicrosoft.com"));
}
@@ -28,8 +28,6 @@ public class PermissionEntryClassificationTests
[Fact]
public void PermissionEntry_FiltersOutLimitedAccess_WhenOnlyPermissionIsLimitedAccess()
{
// A principal whose sole permission level is "Limited Access" should produce
// an empty list after filtering — used to decide whether to include the entry.
var result = PermissionEntryHelper.FilterPermissionLevels(new[] { "Limited Access" });
Assert.Empty(result);
}
@@ -41,23 +39,100 @@ public class PermissionEntryClassificationTests
Assert.Equal(new[] { "Contribute" }, result);
}
// ── IsSharingLinksGroup ────────────────────────────────────────────────────
// ── IsBareLimitedAccessSystemGroup ─────────────────────────────────────────
[Fact]
public void IsSharingLinksGroup_WithSharingLinksPrefix_ReturnsTrue()
public void IsBareLimitedAccessSystemGroup_WithExactMatch_ReturnsTrue()
{
Assert.True(PermissionEntryHelper.IsSharingLinksGroup("SharingLinks.abc123.Edit"));
Assert.True(PermissionEntryHelper.IsBareLimitedAccessSystemGroup("Limited Access System Group"));
}
[Fact]
public void IsSharingLinksGroup_WithLimitedAccessSystemGroup_ReturnsTrue()
public void IsBareLimitedAccessSystemGroup_WithForWebVariant_ReturnsFalse()
{
Assert.True(PermissionEntryHelper.IsSharingLinksGroup("Limited Access System Group"));
// The "For Web {guid}" variant is enriched, not filtered.
Assert.False(PermissionEntryHelper.IsBareLimitedAccessSystemGroup(
"Limited Access System Group For Web e55a4f7a-b132-4baa-bd96-c63d8dc1fc80"));
}
[Fact]
public void IsSharingLinksGroup_WithNormalGroup_ReturnsFalse()
public void IsBareLimitedAccessSystemGroup_WithNormalGroup_ReturnsFalse()
{
Assert.False(PermissionEntryHelper.IsSharingLinksGroup("Owners"));
Assert.False(PermissionEntryHelper.IsBareLimitedAccessSystemGroup("Owners"));
}
// ── Classify ───────────────────────────────────────────────────────────────
[Fact]
public void Classify_WithNormalGroupTitle_ReturnsNone()
{
var c = PermissionEntryHelper.Classify("Site Owners");
Assert.Equal(SystemGroupKind.None, c.Kind);
}
[Fact]
public void Classify_WithBareLimitedAccess_ReturnsLimitedAccessBare()
{
var c = PermissionEntryHelper.Classify("Limited Access System Group");
Assert.Equal(SystemGroupKind.LimitedAccessBare, c.Kind);
}
[Fact]
public void Classify_WithLimitedAccessForWeb_ExtractsWebId()
{
var c = PermissionEntryHelper.Classify(
"Limited Access System Group For Web e55a4f7a-b132-4baa-bd96-c63d8dc1fc80");
Assert.Equal(SystemGroupKind.LimitedAccessWeb, c.Kind);
Assert.Equal(Guid.Parse("e55a4f7a-b132-4baa-bd96-c63d8dc1fc80"), c.WebId);
Assert.Null(c.ListId);
Assert.Null(c.ItemUniqueId);
}
[Fact]
public void Classify_WithLimitedAccessForList_ExtractsListId()
{
var c = PermissionEntryHelper.Classify(
"Limited Access System Group For List b20e3b22-2b09-4c99-9ba4-37b42f3a12dc");
Assert.Equal(SystemGroupKind.LimitedAccessList, c.Kind);
Assert.Equal(Guid.Parse("b20e3b22-2b09-4c99-9ba4-37b42f3a12dc"), c.ListId);
Assert.Null(c.WebId);
Assert.Null(c.ItemUniqueId);
}
[Fact]
public void Classify_WithSharingLink_ExtractsItemAndShareId()
{
var c = PermissionEntryHelper.Classify(
"SharingLinks.e686221e-d1cb-43c5-8c68-04aa7f90f329.OrganizationEdit.64c27910-66ea-421d-b0f0-8f0f72dcfaf6");
Assert.Equal(SystemGroupKind.SharingLink, c.Kind);
Assert.Equal(Guid.Parse("e686221e-d1cb-43c5-8c68-04aa7f90f329"), c.ItemUniqueId);
Assert.Equal(Guid.Parse("64c27910-66ea-421d-b0f0-8f0f72dcfaf6"), c.ShareId);
Assert.Equal("OrganizationEdit", c.LinkType);
}
[Theory]
[InlineData("SharingLinks.e686221e-d1cb-43c5-8c68-04aa7f90f329.AnonymousView.64c27910-66ea-421d-b0f0-8f0f72dcfaf6", "AnonymousView")]
[InlineData("SharingLinks.e686221e-d1cb-43c5-8c68-04aa7f90f329.Flexible.64c27910-66ea-421d-b0f0-8f0f72dcfaf6", "Flexible")]
[InlineData("SharingLinks.e686221e-d1cb-43c5-8c68-04aa7f90f329.OrganizationView.64c27910-66ea-421d-b0f0-8f0f72dcfaf6", "OrganizationView")]
public void Classify_WithVariousSharingLinkTypes_PreservesLinkType(string title, string expected)
{
var c = PermissionEntryHelper.Classify(title);
Assert.Equal(SystemGroupKind.SharingLink, c.Kind);
Assert.Equal(expected, c.LinkType);
}
[Fact]
public void Classify_WithMalformedSharingLink_ReturnsNone()
{
// Missing share GUID at the end
var c = PermissionEntryHelper.Classify("SharingLinks.e686221e-d1cb-43c5-8c68-04aa7f90f329.Edit");
Assert.Equal(SystemGroupKind.None, c.Kind);
}
[Fact]
public void Classify_WithEmptyString_ReturnsNone()
{
var c = PermissionEntryHelper.Classify("");
Assert.Equal(SystemGroupKind.None, c.Kind);
}
}