Skip to content

Commit b95956a

Browse files
authored
Implement better way to test for in-memory file (#645)
* Implement better way to test for in-memory file Fix #569 PSES would crash quite often when the user viewed a ps1 file in a diff window or an earlier version using GitLens. This approach using the System.Uri class that can detect file vs other schemes. URI chokes on relative file paths. In this case, we fall back to the previous approach of using Path.GetFullPath(). * Add unit tests and PTLE catch - just in case. * Use test cases and a single Assert. * Remove test value for verifying we get msg on test fail
1 parent 2523e71 commit b95956a

File tree

2 files changed

+57
-15
lines changed

2 files changed

+57
-15
lines changed

src/PowerShellEditorServices/Workspace/Workspace.cs

+20-12
Original file line numberDiff line numberDiff line change
@@ -390,22 +390,30 @@ internal static bool IsPathInMemory(string filePath)
390390
// view of the current file or an untitled file.
391391
try
392392
{
393-
// NotSupportedException or ArgumentException gets thrown when
394-
// given an invalid path. Since any non-standard path will
395-
// trigger this, assume that it means it's an in-memory file
396-
// unless the path starts with file:
397-
Path.GetFullPath(filePath);
393+
// File system absoulute paths will have a URI scheme of file:.
394+
// Other schemes like "untitled:" and "gitlens-git:" will return false for IsFile.
395+
var uri = new Uri(filePath);
396+
isInMemory = !uri.IsFile;
398397
}
399-
catch (ArgumentException)
398+
catch (UriFormatException)
400399
{
401-
isInMemory = true;
402-
}
403-
catch (NotSupportedException)
404-
{
405-
isInMemory = true;
400+
// Relative file paths cause a UriFormatException.
401+
// In this case, fallback to using Path.GetFullPath().
402+
try
403+
{
404+
Path.GetFullPath(filePath);
405+
}
406+
catch (Exception ex) when (ex is ArgumentException || ex is NotSupportedException)
407+
{
408+
isInMemory = true;
409+
}
410+
catch (PathTooLongException)
411+
{
412+
// If we ever get here, it should be an actual file so, not in memory
413+
}
406414
}
407415

408-
return !filePath.ToLower().StartsWith("file:") && isInMemory;
416+
return isInMemory;
409417
}
410418

411419
private string GetBaseFilePath(string filePath)

test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs

+37-3
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
44
//
55

6-
using Microsoft.PowerShell.EditorServices;
76
using System;
87
using System.IO;
9-
using System.Linq;
10-
using Xunit;
118
using Microsoft.PowerShell.EditorServices.Utility;
9+
using Xunit;
1210

1311
namespace Microsoft.PowerShell.EditorServices.Test.Session
1412
{
@@ -35,5 +33,41 @@ public void CanResolveWorkspaceRelativePath()
3533
Assert.Equal(@"..\PeerPath\FilePath.ps1", workspace.GetRelativePath(testPathOutside));
3634
Assert.Equal(testPathAnotherDrive, workspace.GetRelativePath(testPathAnotherDrive));
3735
}
36+
37+
[Fact]
38+
public void CanDetermineIsPathInMemory()
39+
{
40+
var tempDir = Environment.GetEnvironmentVariable("TEMP");
41+
var shortDirPath = Path.Combine(tempDir, "GitHub", "PowerShellEditorServices");
42+
var shortFilePath = Path.Combine(shortDirPath, "foo.ps1");
43+
var shortUriForm = "git:/c%3A/Users/Keith/GitHub/dahlbyk/posh-git/src/PoshGitTypes.ps1?%7B%22path%22%3A%22c%3A%5C%5CUsers%5C%5CKeith%5C%5CGitHub%5C%5Cdahlbyk%5C%5Cposh-git%5C%5Csrc%5C%5CPoshGitTypes.ps1%22%2C%22ref%22%3A%22~%22%7D";
44+
var longUriForm = "gitlens-git:c%3A%5CUsers%5CKeith%5CGitHub%5Cdahlbyk%5Cposh-git%5Csrc%5CPoshGitTypes%3Ae0022701.ps1?%7B%22fileName%22%3A%22src%2FPoshGitTypes.ps1%22%2C%22repoPath%22%3A%22c%3A%2FUsers%2FKeith%2FGitHub%2Fdahlbyk%2Fposh-git%22%2C%22sha%22%3A%22e0022701fa12e0bc22d0458673d6443c942b974a%22%7D";
45+
46+
var testCases = new[] {
47+
// Test short file absolute paths
48+
new { IsInMemory = false, Path = shortDirPath },
49+
new { IsInMemory = false, Path = shortFilePath },
50+
new { IsInMemory = false, Path = new Uri(shortDirPath).ToString() },
51+
new { IsInMemory = false, Path = new Uri(shortFilePath).ToString() },
52+
53+
// Test short file relative paths - not sure we'll ever get these but just in case
54+
new { IsInMemory = false, Path = "foo.ps1" },
55+
new { IsInMemory = false, Path = ".." + Path.DirectorySeparatorChar + "foo.ps1" },
56+
57+
// Test short non-file paths
58+
new { IsInMemory = true, Path = "untitled:untitled-1" },
59+
new { IsInMemory = true, Path = shortUriForm },
60+
61+
// Test long non-file path - known to have crashed PSES
62+
new { IsInMemory = true, Path = longUriForm },
63+
};
64+
65+
foreach (var testCase in testCases)
66+
{
67+
Assert.True(
68+
Workspace.IsPathInMemory(testCase.Path) == testCase.IsInMemory,
69+
$"Testing path {testCase.Path}");
70+
}
71+
}
3872
}
3973
}

0 commit comments

Comments
 (0)