Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 37 additions & 0 deletions Assets/Tests/Editor/SkillInstallLayoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,43 @@ public void GetSkillSourceInfos_WhenProjectIsCurrentRoot_IncludesCliOnlyCoreSkil
Assert.That(skillSources.Select(skill => skill.Name), Does.Contain("uloop-launch"));
}

// Tests that differently cased paths follow each editor platform's path identity policy.
[TestCase(UnityEngine.RuntimePlatform.WindowsEditor, true)]
[TestCase(UnityEngine.RuntimePlatform.OSXEditor, true)]
[TestCase(UnityEngine.RuntimePlatform.LinuxEditor, false)]
public void HaveSamePathIdentityAtPlatform_WhenCasingDiffers_UsesPlatformPolicy(
UnityEngine.RuntimePlatform platform,
bool expected)
{
string lowerCasePath = Path.Combine(_projectRoot, "case-sensitive-root");
string upperCasePath = Path.Combine(_projectRoot, "CASE-SENSITIVE-ROOT");

bool actual = SkillSourceRootEnumerator.HaveSamePathIdentityAtPlatform(
lowerCasePath,
upperCasePath,
platform);

Assert.That(actual, Is.EqualTo(expected));
}

// Tests that an optional trailing directory separator does not change path identity.
[TestCase(UnityEngine.RuntimePlatform.WindowsEditor)]
[TestCase(UnityEngine.RuntimePlatform.OSXEditor)]
[TestCase(UnityEngine.RuntimePlatform.LinuxEditor)]
public void HaveSamePathIdentityAtPlatform_WhenTrailingSeparatorDiffers_ReturnsTrue(
UnityEngine.RuntimePlatform platform)
{
string path = Path.Combine(_projectRoot, "skill-source-root");
string pathWithTrailingSeparator = path + Path.DirectorySeparatorChar;

bool actual = SkillSourceRootEnumerator.HaveSamePathIdentityAtPlatform(
path,
pathWithTrailingSeparator,
platform);

Assert.That(actual, Is.True);
}

// Tests that Tool Settings can read source skill frontmatter descriptions by tool name.
[Test]
public void GetToolDescriptionsByToolName_WhenSkillHasDescription_MapsDescriptionToToolName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@ private static void AddSkillSourceRoot(
private static string GetCliOnlySkillSourceRoot(string projectRoot)
{
string currentProjectRoot = UnityCliLoopPathResolver.GetProjectRoot();
if (!string.Equals(
Path.GetFullPath(projectRoot),
Path.GetFullPath(currentProjectRoot),
StringComparison.Ordinal))
if (!HaveSamePathIdentityAtPlatform(
projectRoot,
currentProjectRoot,
UnityEngine.Application.platform))
{
return null;
}
Expand All @@ -231,10 +231,45 @@ private static string GetCliOnlySkillSourceRoot(string projectRoot)

private static bool IsCliOnlySkillSourceRoot(string searchRoot)
{
return HaveSamePathIdentityAtPlatform(
searchRoot,
GetCliOnlySkillSourceRoot(UnityCliLoopPathResolver.GetProjectRoot()),
UnityEngine.Application.platform);
}

internal static bool HaveSamePathIdentityAtPlatform(
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
string leftPath,
string rightPath,
RuntimePlatform platform)
{
// Windows and macOS editor paths follow their default case-insensitive filesystem behavior.
// Probing case sensitivity per volume would add I/O and complexity to this CLI-only source gate.
bool usesCaseInsensitivePathIdentity = platform == RuntimePlatform.WindowsEditor
|| platform == RuntimePlatform.OSXEditor;
StringComparison comparison = usesCaseInsensitivePathIdentity
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
return string.Equals(
Path.GetFullPath(searchRoot),
Path.GetFullPath(GetCliOnlySkillSourceRoot(UnityCliLoopPathResolver.GetProjectRoot())),
StringComparison.Ordinal);
NormalizePathForIdentity(leftPath),
NormalizePathForIdentity(rightPath),
comparison);
}

private static string NormalizePathForIdentity(string path)
{
string fullPath = Path.GetFullPath(path);
string root = Path.GetPathRoot(fullPath);
if (!string.IsNullOrEmpty(root) && string.Equals(fullPath, root, StringComparison.OrdinalIgnoreCase))
{
// Trimming the only separator from a filesystem root would change its identity.
return root;
}

string normalizedPath = fullPath.TrimEnd(
Path.DirectorySeparatorChar,
Path.AltDirectorySeparatorChar);
Debug.Assert(!string.IsNullOrEmpty(normalizedPath), "normalizedPath must not be empty");
return normalizedPath;
}

private static IEnumerable<string> EnumerateDirectProjectPackageRoots(string projectRoot)
Expand Down
Loading