-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Make Get-ChildItem continue enumeration when encountering error on contained item (#2856) #3806
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
Changes from all commits
c65e618
cd57775
170f901
43339c0
2e97d00
c7e0b56
fe7dd4b
ba536e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,12 +4,18 @@ Describe "Get-ChildItem" -Tags "CI" { | |
|
||
BeforeAll { | ||
# Create Test data | ||
$null = New-Item -Path $TestDrive -Name "a" -ItemType "File" -Force | ||
$null = New-Item -Path $TestDrive -Name "B" -ItemType "File" -Force | ||
$null = New-Item -Path $TestDrive -Name "c" -ItemType "File" -Force | ||
$null = New-Item -Path $TestDrive -Name "D" -ItemType "File" -Force | ||
$null = New-Item -Path $TestDrive -Name "E" -ItemType "Directory" -Force | ||
$null = New-Item -Path $TestDrive -Name ".F" -ItemType "File" -Force | %{$_.Attributes = "hidden"} | ||
$item_a = "a3fe710a-31af-4834-bc29-d0b584589838" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we use lower case for "_a" and below for "_c"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The original filenames were It does look like I made a copy/paste error when I was generating GUID-based filenames. The filename for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason I used lower-case in the variable names was to call out that casing was significant. |
||
$item_B = "B1B691A9-B7B1-4584-AED7-5259511BEEC4" | ||
$item_c = "c283d143-2116-4809-bf11-4f7d61613f92" | ||
$item_D = "D39B4FD9-3E1D-4DD5-8718-22FE2C934CE3" | ||
$item_E = "EE150FEB-0F21-4AFF-8066-AF59E925810C" | ||
$item_F = ".F81D8514-8862-4227-B041-0529B1656A43" | ||
$null = New-Item -Path $TestDrive -Name $item_a -ItemType "File" -Force | ||
$null = New-Item -Path $TestDrive -Name $item_B -ItemType "File" -Force | ||
$null = New-Item -Path $TestDrive -Name $item_c -ItemType "File" -Force | ||
$null = New-Item -Path $TestDrive -Name $item_D -ItemType "File" -Force | ||
$null = New-Item -Path $TestDrive -Name $item_E -ItemType "Directory" -Force | ||
$null = New-Item -Path $TestDrive -Name $item_F -ItemType "File" -Force | %{$_.Attributes = "hidden"} | ||
} | ||
|
||
It "Should list the contents of the current folder" { | ||
|
@@ -34,32 +40,68 @@ Describe "Get-ChildItem" -Tags "CI" { | |
|
||
It "Should list files in sorted order" { | ||
$files = Get-ChildItem -Path $TestDrive | ||
$files[0].Name | Should Be "E" | ||
$files[1].Name | Should Be "a" | ||
$files[2].Name | Should Be "B" | ||
$files[3].Name | Should Be "c" | ||
$files[4].Name | Should Be "D" | ||
$files[0].Name | Should Be $item_E | ||
$files[1].Name | Should Be $item_a | ||
$files[2].Name | Should Be $item_B | ||
$files[3].Name | Should Be $item_c | ||
$files[4].Name | Should Be $item_D | ||
} | ||
|
||
It "Should list hidden files as well when 'Force' parameter is used" { | ||
$files = Get-ChildItem -path $TestDrive -Force | ||
$files | Should not be $null | ||
$files.Count | Should be 6 | ||
$files.Name.Contains(".F") | ||
$files.Name.Contains($item_F) | Should Be $true | ||
} | ||
|
||
It "Should list only hidden files when 'Hidden' parameter is used" { | ||
$files = Get-ChildItem -path $TestDrive -Hidden | ||
$files | Should not be $null | ||
$files.Count | Should be 1 | ||
$files[0].Name | Should Be ".F" | ||
$files[0].Name | Should Be $item_F | ||
} | ||
It "Should give .sys file if the fullpath is specified with hidden and force parameter" -Skip:(!$IsWindows){ | ||
$file = Get-ChildItem -path "$env:SystemDrive\\pagefile.sys" -Hidden | ||
$file | Should not be $null | ||
$file.Count | Should be 1 | ||
$file.Name | Should be "pagefile.sys" | ||
} | ||
It "Should continue enumerating a directory when a contained item is deleted" { | ||
$Error.Clear() | ||
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("GciEnumerationActionDelete", $true) | ||
$result = Get-ChildItem -Path $TestDrive -ErrorAction SilentlyContinue | ||
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("GciEnumerationActionDelete", $false) | ||
if ($IsWindows) | ||
{ | ||
$Error.Count | Should BeExactly 0 | ||
$result.Count | Should BeExactly 5 | ||
} | ||
else | ||
{ | ||
$Error.Count | Should BeExactly 1 | ||
$Error[0].FullyQualifiedErrorId | Should BeExactly "DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand" | ||
$Error[0].Exception | Should BeOfType System.Io.FileNotFoundException | ||
$result.Count | Should BeExactly 4 | ||
} | ||
} | ||
It "Should continue enumerating a directory when a contained item is renamed" { | ||
$Error.Clear() | ||
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("GciEnumerationActionRename", $true) | ||
$result = Get-ChildItem -Path $TestDrive -ErrorAction SilentlyContinue | ||
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("GciEnumerationActionRename", $false) | ||
if ($IsWindows) | ||
{ | ||
$Error.Count | Should BeExactly 0 | ||
$result.Count | Should BeExactly 4 | ||
} | ||
else | ||
{ | ||
$Error.Count | Should BeExactly 1 | ||
$Error[0].FullyQualifiedErrorId | Should BeExactly "DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand" | ||
$Error[0].Exception | Should BeOfType System.Io.FileNotFoundException | ||
$result.Count | Should BeExactly 3 | ||
} | ||
|
||
} | ||
|
||
Context 'Env: Provider' { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking these 2 testing flags in the loop seems too expensive to me. How about do the testing trick before the foreach loop? Like:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm concerned about hoisting this out of the loop. The point is to have a file go away while the enumeration is in progress. If we do the test outside the loop I don't think we've met the requirement---we've acquired the enumerator but have not yet started the enumeration. That's why we've chosen files that will not be the first in the enumeration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we can put this after
IEnumerable<FileSystemInfo> sortedChildList = childList.OrderBy(c => c.Name, StringComparer.CurrentCultureIgnoreCase);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that solves the problem. Again, we have an enumerable object but enumeration doesn't start until the
foreach
.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we get already the list in
foreach (IEnumerable<FileSystemInfo> childList in target)
- so after that 'IEnumerable sortedChildList = childList.OrderBy(c => c.Name, StringComparer.CurrentCultureIgnoreCase);' we can safely delete/remove test file.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
target
is just aList
ofIEnumerable
objects, containing only 1 or 2 entries---anIEnumerable
for directory names and anIEnumerable
for file names. I don't think the act of getting a reference to an enumerable object from a list causes enumeration to begin.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jeffbi This is a very good point. Let's keep it as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I catched an enumaration issue second time in last week - need to go to school. :-)
The last question is whether to make a test for such normal runtime error?