Merge branch 'master' of https://www.github.com/powershell/powershell into jianyunt/docs

This commit is contained in:
Jianyun Tao 2016-08-02 16:53:23 -07:00
commit 7eae332346
46 changed files with 5047 additions and 215 deletions

View file

@ -20,10 +20,10 @@ You can download and install a PowerShell package for any of the following platf
| Platform | Releases | How to Install |
|--------------|--------------------|--------------------------------|
| Windows | [.msi][rl-windows] | [How to Install][in-windows] |
| Ubuntu 14.04 | [.deb][rl-ubuntu] | [How to Install][in-ubuntu] |
| CentOS 7 | [.rpm][rl-centos] | [How to Install][in-centos] |
| OS X 10.11 | [.pkg][rl-osx] | [How to Install][in-osx] |
| Windows | [.msi][rl-windows] | [Instructions][in-windows] |
| Ubuntu 14.04 | [.deb][rl-ubuntu] | [Instructions][in-ubuntu] |
| CentOS 7 | [.rpm][rl-centos] | [Instructions][in-centos] |
| OS X 10.11 | [.pkg][rl-osx] | [Instructions][in-osx] |
[rl-windows]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.7/PowerShell_6.0.0.7.msi
[rl-ubuntu]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.7/powershell_6.0.0-alpha.7-1_amd64.deb

View file

@ -106,7 +106,7 @@ Start-PSBuild
Congratulations! If everything went right, PowerShell is now built.
The `Start-PSBuild` script will output the location of the executable:
`./src/powershell/bin/Linux/netcoreapp1.0/ubuntu.14.04-x64/powershell`.
`./src/powershell-unix/bin/Linux/netcoreapp1.0/ubuntu.14.04-x64/powershell`.
You should now be running the `powershell` that you just built, if your run the above executable.
You can run our cross-platform Pester tests with `Start-PSPester`, and our xUnit tests with `Start-PSxUnit`.
@ -129,7 +129,7 @@ make test
popd
```
This library will be emitted in the `src/powershell` project,
This library will be emitted in the `src/powershell-unix` project,
where `dotnet` consumes it as "content" and thus automatically deploys it.
Build the managed projects
@ -141,7 +141,7 @@ The `--configuration Linux` flag is necessary to ensure that the preprocessor de
```sh
dotnet restore
cd src/powershell
cd src/powershell-unix
dotnet build --configuration Linux
```

View file

@ -76,6 +76,6 @@ download the `pkg` from our GitHub releases page using your browser, complete th
start a `powershell` session, and use `Start-PSBuild` from the module.
The output directory will be slightly different because your runtime identifier is different.
PowerShell will be at `./src/powershell/bin/Linux/netcoreapp1.0/osx.10.11-x64/powershell`,
PowerShell will be at `./src/powershell-unix/bin/Linux/netcoreapp1.0/osx.10.11-x64/powershell`,
or `osx.10.10` depending on your operating system version.
Note that configration is still `Linux` because it would be silly to make yet another separate configuration when it's used soley to work-around a CLI issue.

View file

@ -72,7 +72,7 @@ Start-PSBuild
```
Congratulations! If everything went right, PowerShell is now built and
executable as `./src/powershell/bin/Debug/netcoreapp1.0/win10-x64/powershell`.
executable as `./src/powershell-win-core/bin/Debug/netcoreapp1.0/win10-x64/powershell`.
This location is of the form
`./[project]/bin/[configuration]/[framework]/[rid]/[binary name]`, and our

View file

@ -48,14 +48,11 @@ Build using our module
Use `Start-PSBuild -FullCLR` from the `build.psm1`
module.
Because the `ConsoleHost` project (*not* the `Host` project) is a
library and not an application (in the sense that .NET CLI does not
emit a native executable using .NET Core's `corehost`), it targets the
framework `netstandard1.6`, *not* `netcoreapp1.0`, and the build
output will *not* have a runtime identifier in the path.
The output location of `powershell.exe` will be
Thus the output location of `powershell.exe` will be
`./src/Microsoft.PowerShell.ConsoleHost/bin/Debug/net451/powershell.exe`
```
.\src\powershell-win-full\bin\Debug\net451\win10-x64\publish\powershell.exe
```
Build manually
==============
@ -99,7 +96,7 @@ This command has a reasonable default to run `powershell.exe` from the build out
If you are building an unusual configuration (i.e. not `Debug`), you can explicitly specify path to the bin directory
```powershell
Start-DevPowerShell -FullCLR -binDir .\src\Microsoft.PowerShell.ConsoleHost\bin\Debug\net451
Start-DevPowerShell -FullCLR -binDir .\src\powershell-win-full\bin\Debug\net451\win10-x64\publish
```
Or more programmatically:

View file

@ -22,7 +22,7 @@ sudo apt-get install libunwind8 libicu52
sudo dpkg -i powershell_6.0.0-alpha.7-1_amd64.deb
```
> Please note that that Ubuntu 16.04 is not yet supported, but coming soon!
> Please note that Ubuntu 16.04 is not yet supported, but coming soon!
[Ubuntu 14.04]: http://releases.ubuntu.com/14.04/

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

41
docs/testing-guidelines/PesterDoAndDont.md Normal file → Executable file
View file

@ -1,23 +1,34 @@
## Do
1. Name your files <description>.tests.ps1
1. Name your files <descriptivetest>.tests.ps1
2. Keep tests simple
1. Test only what you need
2. Reduce dependencies
3. Be sure to tag your Describe blocks with "inner" and "outer"
4. Make sure that Describe/Context/It descriptions are useful
3. Be sure to tag your `Describe` blocks based on their purpose
1. Tag `CI` indicates that it will be run as part of the continuous integration process. These should be unit test like, and generally take less than a second.
2. Tag `Feature` indicates a higher level feature test (we will run these on a regular basis), for example, tests which go to remote resources, or test broader functionality
3. Tag `Scenario` indicates tests of integration with other features (these will be run on a less regular basis and test even broader functionality than feature tests.
4. Make sure that `Describe`/`Context`/`It` descriptions are useful
1. The error message should not be the place where you describe the test
5. Use "Context" to group tests
1. Multiple Contexts can help you group your test suite into logical sections
6. Use BeforeAll/AfterAll/BeforeEach/AfterEach instead of custom initiators
7. Use Try-Catch for expected errors and check $_.fullyQualifiedErrorId
8. Loop It blocks for checking multiple properties
5. Use `Context` to group tests
1. Multiple `Context` blocks can help you group your test suite into logical sections
6. Use `BeforeAll`/`AfterAll`/`BeforeEach`/`AfterEach` instead of custom initiators
7. Prefer Try-Catch for expected errors and check $_.fullyQualifiedErrorId (don't use `should throw`)
8. Use `-testcases` when iterating over multiple `It` blocks
9. Use code coverage functionality where appropriate
10. Use Mock functionality when you don't have your entire environment
11. Avoid free code in a Describe block
1. Use `[Before|After][Each|All]` _see Free Code in a Describe block_
10. Use `Mock` functionality when you don't have your entire environment
11. Avoid free code in a `Describe` block
1. Use `[Before|After][Each|All]` see [Free Code in a Describe block](WritingPesterTests.md#free-code-in-a-describe-block)
12. Avoid creating or using test files outside of TESTDRIVE:
1. TESTDRIVE: has automatic clean-up
13. Keep in mind that we are creating cross platform tests
1. Avoid using the registry
2. Avoid using COM
14. Avoid being too specific about the _count_ of a resource as these can change platform to platform
1. ex: checking for the count of loaded format files, check rather for format data for a specific type
## Don't
1. Have too many evaluations in a single It block
1. The first "Should" failure will stop that block
2. Don't use "Should" anywhere but within an "It" Block
1. Don't have too many evaluations in a single It block
1. The first `Should` failure will stop that block
2. Don't use `Should` outside of an `It` Block
3. Don't use the word "Error" or "Fail" to test a positive case
1. ex: "Get-Childitem TESTDRIVE: shouldn't fail", rather "Get-ChildItem should be able to retrieve file listing from TESTDRIVE"

View file

@ -1,106 +0,0 @@
# DRAFT
_I have more questions than answers_
#### Current Test Infrastructure
We currently rely heavily on STEX environment for our testing, and we will continue to do so through the Server2016 release. We
need to use that current infrastructure to continue to test full PowerShell builds; it should be possible to build automation
which takes a full PowerShell build and lay it on an existing lab system, update the appropriate test files and execute
a test pass in the same way that we do with official builds.
The test artifacts which are applicable to full PowerShell are not universally applicable to Core/Nano/OtherPlatform, we will need
to create tooling which allows us to apply a set of test artifacts to a configuration, and then execute tests. Eventually, we need
to have our CI environment test all the flavors of PowerShell we create.
**Question**: Can AppVeyor/Travis service that need?
#### Organization
**Proposal**: Create 3 tiers of testing:
* Checkin
* These are run as part of the CI process, and should run quickly. How quickly is an open question. We need to determine
the right amount of coverage without spending too much time. It may be that we can improve our coverage here through parallelization
but we have not investigated enough to determine whether it's possible.
* Feature
* the tests which look at corner cases, and stand-alone modules (for example, the archive module tests could fall into this
category)
* Scenario
* these are tests which span features, and determine whether the whole product is working correctly. The current P3 tests fall
largely here
**Actions**: Decide what goes where. My initial thoughts are to migrate our current TTEST unittests into tier 1 (Checkin)
**Current Migration Activity**
We have teams working on migrating tests which are in non-portable frameworks (TTest, Lite1, Lite3, etc) to portable frameworks.
The first effort is to migrate our TTEST cmdlet unit tests to Pester, we should be taking those migrated tests and get them into
SD
##### Layout
We need to have a reasonable layout of our tests, not sure what that looks like yet. We need to make it
easy to find both feature and test code to reduce our maintainance burden.
##### Self Hosting
Self-Hosting remains problematic while are still so early in the development phase, but it is _imperative_
that we dog food as early as possible. This is especially true on the non-Windows platforms where we have made
assumptions about the working environment with regard to a number of issues:
* removal of well known aliases
* case sensitivity of some operations
* coverage
We should be using these non-windows platforms as much as possible to
=======
# DRAFT
_I have more questions than answers_
#### Current Test Infrastructure
We currently rely heavily on STEX environment for our testing, and we will continue to do so through the Server2016 release. We
need to use that current infrastructure to continue to test full PowerShell builds; it should be possible to build automation
which takes a full PowerShell build and lay it on an existing lab system, update the appropriate test files and execute
a test pass in the same way that we do with official builds.
The test artifacts which are applicable to full PowerShell are not universally applicable to Core/Nano/OtherPlatform, we will need
to create tooling which allows us to apply a set of test artifacts to a configuration, and then execute tests. Eventually, we need
to have our CI environment test all the flavors of PowerShell we create.
**Question**: Can AppVeyor/Travis service that need?
#### Organization
**Proposal**: Create 3 tiers of testing:
* Checkin
* These are run as part of the CI process, and should run quickly. How quickly is an open question. We need to determine
the right amount of coverage without spending too much time. It may be that we can improve our coverage here through parallelization
but we have not investigated enough to determine whether it's possible.
* Feature
* the tests which look at corner cases, and stand-alone modules (for example, the archive module tests could fall into this
category)
* Scenario
* these are tests which span features, and determine whether the whole product is working correctly. The current P3 tests fall
largely here
**Actions**: Decide what goes where. My initial thoughts are to migrate our current TTEST unittests into tier 1 (Checkin)
**Current Migration Activity**
We have teams working on migrating tests which are in non-portable frameworks (TTest, Lite1, Lite3, etc) to portable frameworks.
The first effort is to migrate our TTEST cmdlet unit tests to Pester, we should be taking those migrated tests and get them into
SD
##### Layout
We need to have a reasonable layout of our tests, not sure what that looks like yet. We need to make it
easy to find both feature and test code to reduce our maintainance burden.
##### Self Hosting
Self-Hosting remains problematic while are still so early in the development phase, but it is _imperative_
that we dog food as early as possible. This is especially true on the non-Windows platforms where we have made
assumptions about the working environment with regard to a number of issues:
* removal of well known aliases
* case sensitivity of some operations
* coverage
We should be using these non-windows platforms as much as possible to
>>>>>>> Create Testing.md

66
docs/testing-guidelines/WritingPesterTests.md Normal file → Executable file
View file

@ -1,9 +1,13 @@
Because we are planning to continue to extend Pester to support remote/parallel execution, it's important to keep in mind the following when create tests:
### Writing Pester Tests
Note that this document does not replace the documents found in the [Pester](https://github.com/pester/pester "Pester") project. This is just
some quick tips and suggestions for creating Pester tests for this project. The Pester community is vibrant and active, if you have questions
about Pester or creating tests, the [Pester Wiki](https://github.com/pester/pester/wiki) has a lot of great information.
When creating tests, keep the following in mind:
* Tests should not be overly complicated and test too many things
* boil down your tests to their essence, test only what you need
* Tests should be as simple as they can
* Tests should generally not rely on any other test
Examples:
Here's the simplest of tests
@ -27,14 +31,28 @@ Describe "One is really one" {
}
It "1 is really an int" {
$i = 1
$i.GetType().FullName | Should Be System.Int32
$i.GetType() | Should Be "int"
}
}
```
If you are checking for proper errors, do that in a try catch, and then check fully qualified error id
alternatively, you could do the following:
```
Describe "One is really one" {
It "Compare 1 to 1" {
$a = 1
$a | Should be 1
}
It "1 is really an int" {
$i = 1
$i.GetType() | Should Be ([System.Int32])
}
}
```
If you are checking for proper errors, do that in a `try/catch`, and then check `FullyQualifiedErrorId`. Checking against `FullyQualifiedErrorId` is recommended because it does not change based on culture as an error message might.
```
...
it "Error should be PathNotFound" {
it "Get-Item on a nonexisting file should have error PathNotFound" {
try
{
get-item "ThisFileCannotPossiblyExist" -ErrorAction Stop
@ -42,8 +60,7 @@ it "Error should be PathNotFound" {
}
catch
{
$_.FullyQualifiedErrorId |
should be "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand"
$_.FullyQualifiedErrorId | should be "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand"
}
}
```
@ -51,12 +68,10 @@ it "Error should be PathNotFound" {
Note that if get-item were to succeed, a different FullyQualifiedErrorId would be thrown and the test will fail because the FQErrorId is wrong. This is the suggested path because Pester wants to check the error message, which will likely not work here because of localized builds, but the FullyQualifiedErrorId is constant regardless of the locale.
### Describe/Context/It
From an organizational standpoint, a Describe block roughly compares to a LITE3 Test Suite and an It block roughly compares to a LITE3 testcase. Unlike LITE3, individual tests are not prioritized (remember that a test name in Pester is really a descriptive sentence, rather than a name), but a Describe block (TestSuite) may be tagged with a string.
For creation of PowerShell tests, the Describe block is the level of granularity suggested and one of two tags should be used: "Inner" or "Outer". If the tag is not provided, tests in that describe block will be run any time tests are executed.
For creation of PowerShell tests, the Describe block is the level of granularity suggested and one of three tags should be used: "CI", "Feature", or "Scenario". If the tag is not provided, tests in that describe block will be run any time tests are executed.
#### Describe
Creates a logical group of tests. All Mocks and TestDrive contents defined within a Describe block are scoped to that Describe ; they will no longer be present when the Describe block exits. A Describe block may contain any number of Context and It blocks.
Creates a logical group of tests. All Mocks and TestDrive contents defined within a Describe block are scoped to that Describe; they will no longer be present when the Describe block exits. A `Describe block may contain any number of Context and It blocks.
#### Context
Provides logical grouping of It blocks within a single Describe block. Any Mocks defined inside a Context are removed at the end of the Context scope, as are any files or folders added to the TestDrive during the Context block's execution. Any BeforeEach or AfterEach blocks defined inside a Context also only apply to tests within that Context .
@ -92,16 +107,7 @@ Describe "Add-Footer" {
When this test completes, the contents of the TestDrive PSDrive will be removed.
#### Parameter Generation
This is quite a bit different from LITE3, but still possible, see the following:
```
Describe "A test" {
function Test-Xor {
param ($a, $b, $ExpectedResult)
It ("Applies XOR to inputs {0} and {1}" -f $a, $b) {
$a -xor $b | Should be $ExpectedResult
}
}
$testCases = @(
@{ a = 0; b = 1; ExpectedResult = 1 }
@ -109,13 +115,16 @@ $testCases = @(
@{ a = 1; b = 1; ExpectedResult = 0 }
@{ a = 0; b = 0; ExpectedResult = 0 }
)
foreach ($testCase in $testCases) {
Test-Xor @testCase
}
Describe "A test" {
It "<a> -xor <b> should be <expectedresult>" -testcase $testcases {
param ($a, $b, $ExpectedResult)
$a -xor $b | Should be $ExpectedResult
}
}
```
You can construct the values to pass as parameters, including the expected value, and use that iteratively in a loop. Note the location of the `It` block
You can also construct loops and pass values as parameters, including the expected value, but Pester does this for you.
#### Mocking
Mocks the behavior of an existing command with an alternate implementation. This creates new behavior for any existing command within the scope of a Describe or Context block. The function allows you to specify a script block that will become the command's new behavior.
@ -128,7 +137,7 @@ Context "Get-Random is not random" {
}
}
```
More information may be found here: https://github.com/pester/Pester/wiki/Mock
More information may be found on the [wiki](https://github.com/pester/Pester/wiki/Mock)
### Free Code in a Describe block
Code execution in Pester can be very subtle and can cause issues when executing test code. The execution of code which lays outside of the usual code blocks may not happen as you expect. Consider the following:
```
@ -138,14 +147,14 @@ Describe it {
Write-Host -for DarkRed "Before BeforeAll"
BeforeAll { write-host -for Blue "In Context BeforeAll" }
Write-Host -for DarkRed "After BeforeAll"
 
Write-Host -for DarkRed "Before AfterAll"
AfterAll { Write-Host -for Blue "In Context AfterAll" }
Write-Host -for DarkRed "After AfterAll"
 
BeforeEach { Write-Host -for Blue "In BeforeEach" }
AfterEach { Write-Host -for Blue "In AfterEach" }
 
Write-Host -for DarkRed "Before It"
It "should not be a surprise" {
1 | should be 1
@ -189,3 +198,4 @@ The DESCRIBE BeforeAll block is executed before any other code even though it wa
Generally, you should have code reside in one of the code block elements of `[Before|After][All|Each]`, especially if those block rely on state set by free code elsewhere in the block.

138
docs/testing-guidelines/testing-guidelines.md Normal file → Executable file
View file

@ -1,7 +1,135 @@
author: Jim
# Testing Guidelines
Testing is a critical part of the PowerShell project.
The PowerShell team created nearly 100,000 tests over the last 12 years which we run as part of the release process for PowerShell in Windows.
Having all of those tests available for the initial release of OPS was not feasible, and we have targeted those tests which
we believe will provide us the ability to catch regressions in the areas which have had the largest changes for OPS. It is our
intent to continue to release more and more of our tests until we have the coverage we need.
For creating new tests, please review the
[documents](https://github.com/PowerShell/PowerShell/tree/master/docs/testing-guidelines) on how to
create tests for OpenPowerShell
## CI System
We use [AppVeyor](http://www.appveyor.com/) as a continuous integration (CI) system for Windows
and [Travis CI](http://www.travis-ci.com) for non-Windows platforms.
### AppVeyor
In the `README.md` at the top of the repo, you can see AppVeyor badge.
It indicates the last build status of `master` branch.
Hopefully, it's green:
![AppVeyor-Badge-Green.png](Images/AppVeyor-Badge-Green.png)
This badge is **clickable**; you can open corresponding build page with logs, artifacts and tests results.
From there you can easily navigate to the build history.
### Travis CI
Travis CI works similarly to AppVeyor. For Travis CI there will be multiple badges:
The badges indicate the last build status of `master` branch for different platforms.
Hopefully, each badge is green:
![Travis-CI-Badge-Green.png](Images/Travis-CI-Badge-Green.png)
This badge is **clickable**; you can open corresponding build page with logs, artifacts and tests results.
From there you can easily navigate to the build history.
### Getting CI Results
CI System builds (Appveyor and Travis CI) and runs tests on every pull request and provides quick feedback about it.
![AppVeyor-Github](Images/AppVeyor-Github.png)
These green check boxes and red crosses are **clickable** as well.
They will bring you to the corresponding page with details.
## Test Frameworks
### Pester
Our script based test framework is [Pester](https://github.com/Pester/Pester). This is the framework which we are using internally
at Microsoft for new script based tests, and a large number of the tests which are part of the OPS project have been migrated from that test base. Pester tests can be used to test most of PowerShell behavior (even some API operations can
easily be tested in Pester)
Substantial changes were required, to get Pester executing on Non-Windows systems. These changes are not yet in the
official Pester code base. Some features of Pester may not be available or may have incorrect behavior. Please make sure
to create issues in [PowerShell/PowerShell](https://github.com/PowerShell/PowerShell/issues) (not Pester) for anything that you find.
### xUnit
For those tests which are not easily run via Pester, we have decided to use [xUnit](https://xunit.github.io/) as the test framework.
Currently, we have a minuscule number of tests which are run via xUnit,
## Running Tests outside of CI
When working on new features or fixes, it is natural to want to run those tests locally before
making a PR. Two helper functions are part of the build.psm1 module to help with that:
* `Start-PSPester` will execute all Pester tests which are run by the CI system
* `Start-PSxUnit` will execute the available xUnit tests run by the CI system
Our CI system runs these as well; there should be no difference between running these on your dev system, versus in CI.
When running tests in this way, be sure that you have started PowerShell with `-noprofile` as some tests will fail if the
environment is not the default or has any customization.
for example, to run all the Pester tests for CI (assuming you are at the root the PowerShell repo):
```
import-module ./build.psm1
Start-PSPester
```
if you wish to run specific tests, that is possible as well:
```
Start-PSPester -Directory test/powershell/engine/Api
```
or a specific Pester test file:
```
Start-PSPester -Directory test/powershell/engine/Api -Test XmlAdapter.Tests.Api
```
### What happens after your PR?
When your PR has successfully passed the CI test gates, your changes will be used to create PowerShell binaries which can be run
in Microsoft's internal test frameworks. The tests that you created for your change and the library of historical tests will be
run to determine if any regressions are present. If these tests find regressions, you'll be notified that your PR is not ready, and provide
you enough information for you to investigate why the failure happened.
> Jason/Jim: Testing requirements (code coverage, required for incoming features/enhancements)
> local build/test execution instructions
> tools needed for build/test execution
> our CI explained
## Test Layout
We have taken a functional approach to the layout of our Pester tests. You should place new tests in their appropriate
location. If you are making a fix to a cmdlet in a module, the test belongs in the module directory.
If you are unsure; you can make it part of your PR, or create an issue. The current layout of tests is:
* test/powershell/engine
* test/powershell/engine/Api
* test/powershell/engine/Basic
* test/powershell/engine/ETS
* test/powershell/engine/Help
* test/powershell/engine/Logging
* test/powershell/engine/Module
* test/powershell/engine/ParameterBinding
* test/powershell/engine/Runspace
* test/powershell/engine/Logging/MessageAnalyzer
* test/powershell/Host
* test/powershell/Host/ConsoleHost
* test/powershell/Host/TabCompletion
* test/powershell/Language
* test/powershell/Modules
* test/powershell/Provider
* test/powershell/Scripting
* test/powershell/Scripting/Debugging
* test/powershell/Scripting/NativeExecution
* test/powershell/SDK
* test/powershell/Security
* test/powershell/Language/Classes
* test/powershell/Language/Interop
* test/powershell/Language/Operators
* test/powershell/Language/Parser
* test/powershell/Language/Interop/DotNet
* test/powershell/Modules/Microsoft.PowerShell.Archive
* test/powershell/Modules/Microsoft.PowerShell.Core
* test/powershell/Modules/Microsoft.PowerShell.Diagnostics
* test/powershell/Modules/Microsoft.PowerShell.Management
* test/powershell/Modules/Microsoft.PowerShell.Security
* test/powershell/Modules/Microsoft.PowerShell.Utility
* test/powershell/Modules/Microsoft.PowerShell.Security
* test/powershell/Modules/PSReadLine

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PackageManagement.ArchiverProviders",
"version": "1.0.0-*",
"authors": ["quoct"],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PackageManagement.CoreProviders",
"version": "1.0.0-*",
"authors": ["quoct"],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PackageManagement.MetaProvider.PowerShell",
"version": "1.0.0-*",
"authors": ["quoct"],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PackageManagement.MsiProvider",
"version": "1.0.0-*",
"authors": ["quoct"],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PackageManagement.MsuProvider",
"version": "1.0.0-*",
"authors": ["quoct"],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PackageManagement.NuGetProvider",
"version": "1.0.0-*",
"authors": ["quoct"],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PackageManagement.PackageSourceListProvider",
"version": "1.0.0-*",
"authors": [ "quoct" ],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PackageManagement",
"version": "1.0.0-*",
"authors": [ "quoct" ],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PowerShell.PackageManagement",
"version": "1.0.0-*",
"authors": ["quoct"],
"buildOptions": {
"warningsAsErrors": true

View file

@ -1,7 +1,6 @@
{
"name": "Microsoft.PowerShell.Workflow.ServiceCore",
"version": "1.0.0-*",
"authors": [ "OPS" ],
"buildOptions": {
"nowarn": [ "CS1570" ],

View file

@ -662,13 +662,13 @@ function CompressSingleDirHelper
}
else
{
$modifiedSourceDirFullName = $sourceDirFullName + "\"
$modifiedSourceDirFullName = $sourceDirFullName + ([io.path]::DirectorySeparatorChar)
}
}
else
{
$sourceDirFullName = $sourceDirPath
$modifiedSourceDirFullName = $sourceDirFullName + "\"
$modifiedSourceDirFullName = $sourceDirFullName + ([io.path]::DirectorySeparatorChar)
}
$dirContents = Get-ChildItem -LiteralPath $sourceDirPath -Recurse
@ -688,7 +688,7 @@ function CompressSingleDirHelper
$files = $currentContent.GetFiles()
if($files.Count -eq 0)
{
$subDirFiles.Add($currentContent.FullName + "\")
$subDirFiles.Add($currentContent.FullName + ([io.path]::DirectorySeparatorChar))
}
}
}
@ -780,7 +780,7 @@ function ZipArchiveHelper
# If a directory needs to be added to an archive file,
# by convention the .Net API's expect the path of the diretcory
# to end with '\' to detect the path as an directory.
if(!$relativeFilePath.EndsWith("\", [StringComparison]::OrdinalIgnoreCase))
if(!$relativeFilePath.EndsWith(([io.path]::DirectorySeparatorChar), [StringComparison]::OrdinalIgnoreCase))
{
try
{
@ -951,7 +951,7 @@ function ExpandArchiveHelper
# The current archive entry is an empty directory
# The FullName of the Archive Entry representing a directory would end with a trailing '\'.
if($extension -eq [string]::Empty -and
$currentArchiveEntryPath.EndsWith("\", [StringComparison]::OrdinalIgnoreCase))
$currentArchiveEntryPath.EndsWith(([io.path]::DirectorySeparatorChar), [StringComparison]::OrdinalIgnoreCase))
{
$pathExists = Test-Path -LiteralPath $currentArchiveEntryPath

View file

@ -2299,9 +2299,11 @@ namespace System.Management.Automation.Remoting.Client
#region DllImports ClientAPI
#if !UNIX
internal const string WSManApiDll = @"WsmSvc.dll";
internal const string WSManClientApiDll = @"WsmSvc.dll";
internal const string WSManProviderApiDll = @"WsmSvc.dll";
#else
internal const string WSManApiDll = @"libpsrpomiprov";
internal const string WSManClientApiDll = @"libpsrpclient";
internal const string WSManProviderApiDll = @"libpsrpomiprov";
#endif
/// <summary>
@ -2315,7 +2317,7 @@ namespace System.Management.Automation.Remoting.Client
/// </param>
/// <returns>
/// </returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManInitialize(int flags,
[In, Out] ref IntPtr wsManAPIHandle);
@ -2329,7 +2331,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="wsManAPIHandle"></param>
/// <param name="flags"></param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManDeinitialize(IntPtr wsManAPIHandle, int flags);
/// <summary>
@ -2348,7 +2350,7 @@ namespace System.Management.Automation.Remoting.Client
/// </param>
/// <param name="wsManSessionHandle"></param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManCreateSession(IntPtr wsManAPIHandle,
[MarshalAs(UnmanagedType.LPWStr)]string connection,
int flags,
@ -2364,7 +2366,7 @@ namespace System.Management.Automation.Remoting.Client
/// </summary>
/// <param name="wsManSessionHandle"></param>
/// <param name="flags"></param>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManCloseSession(IntPtr wsManSessionHandle,
int flags);
@ -2389,7 +2391,7 @@ namespace System.Management.Automation.Remoting.Client
}
}
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManSetSessionOption(IntPtr wsManSessionHandle,
WSManSessionOption option,
IntPtr data);
@ -2404,7 +2406,7 @@ namespace System.Management.Automation.Remoting.Client
/// An int (DWORD) data.
/// </param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManGetSessionOptionAsDword(IntPtr wsManSessionHandle,
WSManSessionOption option,
out int value);
@ -2460,7 +2462,7 @@ namespace System.Management.Automation.Remoting.Client
return returnval;
}
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
private static extern int WSManGetSessionOptionAsString(IntPtr wsManSessionHandle,
WSManSessionOption option,
int optionLength,
@ -2510,7 +2512,7 @@ namespace System.Management.Automation.Remoting.Client
openContent, asyncCallback, ref shellOperationHandle);
}
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManCreateShellEx", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManCreateShellEx", SetLastError = false, CharSet = CharSet.Unicode)]
private static extern void WSManCreateShellExInternal(IntPtr wsManSessionHandle,
int flags,
[MarshalAs(UnmanagedType.LPWStr)]string resourceUri,
@ -2532,7 +2534,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="connectXml"></param>
/// <param name="asyncCallback"></param>
/// <param name="shellOperationHandle"></param>
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManConnectShell", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManConnectShell", SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManConnectShellEx(IntPtr wsManSessionHandle,
int flags,
[MarshalAs(UnmanagedType.LPWStr)]string resourceUri,
@ -2550,7 +2552,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="flags"></param>
/// <param name="disconnectInfo"></param>
/// <param name="asyncCallback"></param>
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManDisconnectShell", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManDisconnectShell", SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManDisconnectShellEx(IntPtr wsManSessionHandle,
int flags,
IntPtr disconnectInfo,
@ -2562,13 +2564,13 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="wsManSessionHandle"></param>
/// <param name="flags"></param>
/// <param name="asyncCallback"></param>
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManReconnectShell", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManReconnectShell", SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManReconnectShellEx(IntPtr wsManSessionHandle,
int flags,
IntPtr asyncCallback);
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManReconnectShellCommand", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManReconnectShellCommand", SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManReconnectShellCommandEx(IntPtr wsManCommandHandle,
int flags,
IntPtr asyncCallback);
@ -2597,7 +2599,7 @@ namespace System.Management.Automation.Remoting.Client
/// An out parameter referening a WSMan shell operation handle
/// for this command.
/// </param>
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManRunShellCommandEx", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManRunShellCommandEx", SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManRunShellCommandEx(IntPtr shellOperationHandle,
int flags,
[MarshalAs(UnmanagedType.LPWStr)]
@ -2610,7 +2612,7 @@ namespace System.Management.Automation.Remoting.Client
ref IntPtr commandOperationHandle);
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManConnectShellCommand", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManConnectShellCommand", SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManConnectShellCommandEx(IntPtr shellOperationHandle,
int flags,
[MarshalAs(UnmanagedType.LPWStr)]
@ -2646,7 +2648,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="receiveOperationHandle">
/// handle to use to cancel the operation.
/// </param>
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManReceiveShellOutput", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManReceiveShellOutput", SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManReceiveShellOutputEx(IntPtr shellOperationHandle,
IntPtr commandOperationHandle,
int flags,
@ -2685,7 +2687,7 @@ namespace System.Management.Automation.Remoting.Client
streamData, false, asyncCallback, ref sendOperationHandle);
}
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManSendShellInput", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManSendShellInput", SetLastError = false, CharSet = CharSet.Unicode)]
private static extern void WSManSendShellInputExInternal(IntPtr shellOperationHandle,
IntPtr commandOperationHandle,
int flags,
@ -2710,7 +2712,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="asyncCallback">
/// callback to notify when the operation completes.
/// </param>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManCloseShell(IntPtr shellHandle,
int flags,
IntPtr asyncCallback);
@ -2726,7 +2728,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="asyncCallback">
/// callback to notify when the operation completes.
/// </param>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManCloseCommand(IntPtr cmdHandle,
int flags,
IntPtr asyncCallback);
@ -2742,7 +2744,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="code"></param>
/// <param name="asyncCallback"></param>
/// <param name="signalOperationHandle"></param>
[DllImport(WSManNativeApi.WSManApiDll, EntryPoint = "WSManSignalShell", SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, EntryPoint = "WSManSignalShell", SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManSignalShellEx(IntPtr shellOperationHandle,
IntPtr cmdOperationHandle,
int flags,
@ -2761,7 +2763,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="operationHandle"></param>
/// <param name="flags"></param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManCloseOperation(IntPtr operationHandle, int flags);
/// <summary>
@ -2858,7 +2860,7 @@ namespace System.Management.Automation.Remoting.Client
/// It cannot be NULL. If both "messageLength" and "message" parameters are 0, the function will return ERROR_INSUFFICIENT_BUFFER
/// and "messageLengthUsed" parameter will be set to the number of characters needed, including NULL terminator
/// </param>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManClientApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManGetErrorMessage(IntPtr wsManAPIHandle,
int flags,
string languageCode,
@ -2879,7 +2881,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="flags">Specifies the options that are available for retrieval.</param>
/// <param name="data">Specifies the result object (WSMAN_DATA).</param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManProviderApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManPluginGetOperationParameters(
IntPtr requestDetails,
int flags,
@ -2895,7 +2897,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="errorCode">Reports any failure in the operation. Terminates on non-NO_ERROR status.</param>
/// <param name="extendedInformation">XML document containing extra error information.</param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManProviderApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManPluginOperationComplete(
IntPtr requestDetails,
int flags,
@ -2942,7 +2944,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="commandState">Specifies the state of the command. It must be set to a value specified by the plugin.</param>
/// <param name="exitCode">Only set when the commandState is terminating.</param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManProviderApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManPluginReceiveResult(
IntPtr requestDetails,
int flags,
@ -2961,7 +2963,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="flags"></param>
/// <param name="context">Defines the value to pass into all future shell and command operations. Represents either the shell or the command.</param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManProviderApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int WSManPluginReportContext(
IntPtr requestDetails,
int flags,
@ -2974,7 +2976,7 @@ namespace System.Management.Automation.Remoting.Client
/// <param name="shutdownCallback">Callback to be executed on shutdown</param>
/// <param name="shutdownContext"></param>
/// <returns></returns>
[DllImport(WSManNativeApi.WSManApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
[DllImport(WSManNativeApi.WSManProviderApiDll, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern void WSManPluginRegisterShutdownCallback(
IntPtr requestDetails,
IntPtr shutdownCallback,

View file

@ -0,0 +1,980 @@
<############################################################################################
# File: Pester.Commands.Cmdlets.ArchiveTests.ps1
# Commands.Cmdlets.ArchiveTests suite contains Tests that are
# used for validating Microsoft.PowerShell.Archive module.
############################################################################################>
$script:TestSourceRoot = $PSScriptRoot
Describe "Test suite for Microsoft.PowerShell.Archive module" -Tags "CI" {
AfterAll {
$global:ProgressPreference = $_progressPreference
$env:PSMODULEPATH = $_modulePath
}
BeforeAll {
# remove the archive module forcefully, to be sure we get the correct version
if ( Get-Module Microsoft.PowerShell.Archive. ) {
Remove-Module Microsoft.PowerShell.Archive -force
}
# Version comparisons should use a System.Version rather than SemanticVersion
$PSVersion = $PSVersionTable.PSVersion -as [Version]
# Write-Progress not supported yet on Core
$_progressPreference = $ProgressPreference
# we need to be sure that we get the correct archive module
$_modulePath = $env:PSMODULEPATH
$powershellexe = (get-process -pid $PID).MainModule.FileName
$env:PSMODULEPATH = join-path ([io.path]::GetDirectoryName($powershellexe)) Modules
if ( $IsCoreCLR ) { $global:ProgressPreference = "SilentlyContinue" }
Setup -d SourceDir
Setup -d SourceDir/ChildDir-1
Setup -d SourceDir/ChildDir-2
Setup -d SourceDir/ChildEmptyDir
$content = "Some Data"
$Files = ( [io.path]::Combine("SourceDir","Sample-1.txt")), ([io.path]::Combine("SourceDir","Sample-2.txt")),
([io.path]::Combine("SourceDir","ChildDir-1","Sample-3.txt")), ([io.path]::Combine("SourceDir","ChildDir-1","Sample-4.txt")),
([io.path]::Combine("SourceDir","ChildDir-2","Sample-5.txt")), ([io.path]::Combine("SourceDir","ChildDir-2","Sample-6.txt"))
foreach($file in $files ) {
Setup -f $file -content $content
}
Setup -f Sample.unzip -content "Some Text"
Setup -f Sample.cab -content "Some Text"
$preCreatedArchivePath = Join-Path $script:TestSourceRoot "SamplePreCreatedArchive.archive"
Copy-Item $preCreatedArchivePath $TestDrive/SamplePreCreatedArchive.zip -Force
}
function Add-CompressionAssemblies {
Add-Type -AssemblyName System.IO.Compression
if (($psedition -eq "Core") -or $IsCoreCLR )
{
Add-Type -AssemblyName System.IO.Compression.ZipFile
}
else
{
Add-Type -AssemblyName System.IO.Compression.FileSystem
}
}
function CompressArchivePathParameterSetValidator {
param
(
[string[]] $path,
[string] $destinationPath,
[string] $compressionLevel = "Optimal"
)
try
{
Compress-Archive -Path $path -DestinationPath $destinationPath -CompressionLevel $compressionLevel
trow "ValidateNotNullOrEmpty attribute is missing on one of parameters belonging to Path parameterset."
}
catch
{
$_.FullyQualifiedErrorId | Should Be "ParameterArgumentValidationError,Compress-Archive"
}
}
function CompressArchiveLiteralPathParameterSetValidator {
param
(
[string[]] $literalPath,
[string] $destinationPath,
[string] $compressionLevel = "Optimal"
)
try
{
Compress-Archive -LiteralPath $literalPath -DestinationPath $destinationPath -CompressionLevel $compressionLevel
throw "ValidateNotNullOrEmpty attribute is missing on one of parameters belonging to LiteralPath parameterset."
}
catch
{
$_.FullyQualifiedErrorId | Should Be "ParameterArgumentValidationError,Compress-Archive"
}
}
function CompressArchiveInValidPathValidator {
param
(
[string[]] $path,
[string] $destinationPath,
[string] $invalidPath,
[string] $expectedFullyQualifiedErrorId
)
try
{
Compress-Archive -Path $path -DestinationPath $destinationPath
throw "Failed to validate that an invalid Path $invalidPath was supplied as input to Compress-Archive cmdlet."
}
catch
{
$_.FullyQualifiedErrorId | Should Be $expectedFullyQualifiedErrorId
}
}
function CompressArchiveInValidArchiveFileExtensionValidator {
param
(
[string[]] $path,
[string] $destinationPath,
[string] $invalidArchiveFileExtension
)
try
{
Compress-Archive -Path $path -DestinationPath $destinationPath
throw "Failed to validate that an invalid archive file format $invalidArchiveFileExtension was supplied as input to Compress-Archive cmdlet."
}
catch
{
$_.FullyQualifiedErrorId | Should Be "NotSupportedArchiveFileExtension,Compress-Archive"
}
}
function Validate-ArchiveEntryCount {
param
(
[string] $path,
[int] $expectedEntryCount
)
Add-CompressionAssemblies
try
{
$archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open)
$archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs
$zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false)
$zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs
$actualEntryCount = $zipArchive.Entries.Count
$actualEntryCount | Should Be $expectedEntryCount
}
finally
{
if ($null -ne $zipArchive) { $zipArchive.Dispose()}
if ($null -ne $archiveFileStream) { $archiveFileStream.Dispose() }
}
}
function ArchiveFileEntryContentValidator {
param
(
[string] $path,
[string] $entryFileName,
[string] $expectedEntryFileContent
)
Add-CompressionAssemblies
try
{
$destFile = "$TestDrive/ExpandedFile"+([System.Guid]::NewGuid().ToString())+".txt"
$archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open)
$archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs
$zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false)
$zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs
$entryToBeUpdated = $zipArchive.Entries | ? {$_.FullName -eq $entryFileName}
if($entryToBeUpdated -ne $null)
{
$srcStream = $entryToBeUpdated.Open()
$destStream = New-Object "System.IO.FileStream" -ArgumentList( $destFile, [System.IO.FileMode]::Create )
$srcStream.CopyTo( $destStream )
$destStream.Dispose()
$srcStream.Dispose()
Get-Content $destFile | Should Be $expectedEntryFileContent
}
else
{
throw "Failed to find the file $entryFileName in the archive file $path"
}
}
finally
{
if ($zipArchive)
{
$zipArchive.Dispose()
}
if ($archiveFileStream)
{
$archiveFileStream.Dispose()
}
}
}
function ExpandArchiveInvalidParameterValidator {
param
(
[boolean] $isLiteralPathParameterSet,
[string[]] $path,
[string] $destinationPath,
[string] $expectedFullyQualifiedErrorId
)
try
{
if($isLiteralPathParameterSet)
{
Expand-Archive -LiteralPath $literalPath -DestinationPath $destinationPath
}
else
{
Expand-Archive -Path $path -DestinationPath $destinationPath
}
throw "Expand-Archive did NOT throw expected error"
}
catch
{
$_.FullyQualifiedErrorId | Should Be $expectedFullyQualifiedErrorId
}
}
Context "Compress-Archive - Parameter validation test cases" {
It "Validate errors from Compress-Archive with NULL & EMPTY values for Path, LiteralPath, DestinationPath, CompressionLevel parameters" {
$sourcePath = "$TestDrive/SourceDir"
$destinationPath = "$TestDrive/SampleSingleFile.zip"
CompressArchivePathParameterSetValidator $null $destinationPath
CompressArchivePathParameterSetValidator $sourcePath $null
CompressArchivePathParameterSetValidator $null $null
CompressArchivePathParameterSetValidator "" $destinationPath
CompressArchivePathParameterSetValidator $sourcePath ""
CompressArchivePathParameterSetValidator "" ""
CompressArchivePathParameterSetValidator $null $null "NoCompression"
CompressArchiveLiteralPathParameterSetValidator $null $destinationPath
CompressArchiveLiteralPathParameterSetValidator $sourcePath $null
CompressArchiveLiteralPathParameterSetValidator $null $null
CompressArchiveLiteralPathParameterSetValidator "" $destinationPath
CompressArchiveLiteralPathParameterSetValidator $sourcePath ""
CompressArchiveLiteralPathParameterSetValidator "" ""
CompressArchiveLiteralPathParameterSetValidator $null $null "NoCompression"
CompressArchiveLiteralPathParameterSetValidator $sourcePath $destinationPath $null
CompressArchiveLiteralPathParameterSetValidator $sourcePath $destinationPath ""
}
It "Validate errors from Compress-Archive when invalid path (non-existing path / non-filesystem path) is supplied for Path or LiteralPath parameters" {
CompressArchiveInValidPathValidator "$TestDrive/InvalidPath" $TestDrive "$TestDrive/InvalidPath" "ArchiveCmdletPathNotFound,Compress-Archive"
if ( ! $IsCoreCLR ) {
CompressArchiveInValidPathValidator "HKLM:/SOFTWARE" $TestDrive "HKLM:/SOFTWARE" "PathNotFound,Compress-Archive"
}
CompressArchiveInValidPathValidator "$TestDrive" "$TestDrive/NonExistingDirectory/sample.zip" "$TestDrive/NonExistingDirectory/sample.zip" "ArchiveCmdletPathNotFound,Compress-Archive"
$path = @("$TestDrive", "$TestDrive/InvalidPath")
CompressArchiveInValidPathValidator $path $TestDrive "$TestDrive/InvalidPath" "ArchiveCmdletPathNotFound,Compress-Archive"
if ( ! $IsCoreCLR ) {
$path = @("$TestDrive", "HKLM:/SOFTWARE")
CompressArchiveInValidPathValidator $path $TestDrive "HKLM:/SOFTWARE" "PathNotFound,Compress-Archive"
}
$invalidUnZipFileFormat = "$TestDrive/Sample.unzip"
CompressArchiveInValidArchiveFileExtensionValidator $TestDrive "$invalidUnZipFileFormat" ".unzip"
$invalidcabZipFileFormat = "$TestDrive/Sample.cab"
CompressArchiveInValidArchiveFileExtensionValidator $TestDrive "$invalidcabZipFileFormat" ".cab"
}
It "Validate error from Compress-Archive when archive file already exists and -Update parameter is not specified" {
$sourcePath = "$TestDrive/SourceDir"
$destinationPath = "$TestDrive/ValidateErrorWhenUpdateNotSpecified.zip"
try
{
"Some Data" > $destinationPath
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
throw "Failed to validate that an archive file format $destinationPath already exists and -Update switch parameter is not specified while running Compress-Archive command."
}
catch
{
$_.FullyQualifiedErrorId | Should Be "ArchiveFileExists,Compress-Archive"
}
}
It "Validate error from Compress-Archive when duplicate paths are supplied as input to Path parameter" {
$sourcePath = @(
"$TestDrive/SourceDir/Sample-1.txt",
"$TestDrive/SourceDir/Sample-1.txt")
$destinationPath = "$TestDrive/DuplicatePaths.zip"
try
{
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
throw "Failed to detect that duplicate Path $sourcePath is supplied as input to Path parameter."
}
catch
{
$_.FullyQualifiedErrorId | Should Be "DuplicatePathFound,Compress-Archive"
}
}
It "Validate error from Compress-Archive when duplicate paths are supplied as input to LiteralPath parameter" {
$sourcePath = @(
"$TestDrive/SourceDir/Sample-1.txt",
"$TestDrive/SourceDir/Sample-1.txt")
$destinationPath = "$TestDrive/DuplicatePaths.zip"
try
{
Compress-Archive -LiteralPath $sourcePath -DestinationPath $destinationPath
throw "Failed to detect that duplicate Path $sourcePath is supplied as input to LiteralPath parameter."
}
catch
{
$_.FullyQualifiedErrorId | Should Be "DuplicatePathFound,Compress-Archive"
}
}
It "Validate that relative path can be specified as Path parameter of Compress-Archive cmdlet" {
$sourcePath = "./SourceDir"
$destinationPath = "RelativePathForPathParameter.zip"
try {
push-location $TESTDRIVE
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
finally {
Pop-Location
}
}
It "Validate that relative path can be specified as LiteralPath parameter of Compress-Archive cmdlet" {
$sourcePath = "./SourceDir"
$destinationPath = "RelativePathForLiteralPathParameter.zip"
try {
push-location $TESTDRIVE
Compress-Archive -LiteralPath $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
finally {
Pop-Location
}
}
It "Validate that relative path can be specified as DestinationPath parameter of Compress-Archive cmdlet" {
$sourcePath = "$TestDrive/SourceDir"
$destinationPath = "./RelativePathForDestinationPathParameter.zip"
try {
push-location $TESTDRIVE
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
finally {
Pop-Location
}
}
}
Context "Compress-Archive - functional test cases" {
It "Validate that a single file can be compressed using Compress-Archive cmdlet" {
$sourcePath = [io.path]::Combine("$TestDrive","SourceDir","ChildDir-1","Sample-3.txt")
$destinationPath = [io.path]::Combine("$TestDrive","SampleSingleFile.zip")
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
$destinationPath | Should Exist
}
# This test requires a fix in PS5 to support reading paths with square bracket
It "Validate that Compress-Archive cmdlet can accept LiteralPath parameter with Special Characters" -skip:($PSVersion -lt "5.0") {
$sourcePath = "$TestDrive/SourceDir/ChildDir-1/Sample[]File.txt"
"Some Random Content" | Out-File -LiteralPath $sourcePath
$destinationPath = "$TestDrive/SampleSingleFileWithSpecialCharacters.zip"
try
{
Compress-Archive -LiteralPath $sourcePath -DestinationPath $destinationPath
$destinationPath | Should Exist
}
finally
{
get-item -literalPath $sourcePath | remove-Item -force
# Remove-Item -LiteralPath $sourcePath -Force
}
}
It "Validate that Compress-Archive cmdlet errors out when DestinationPath resolves to multiple locations" {
New-Item $TestDrive/SampleDir/Child-1 -Type Directory -Force | Out-Null
New-Item $TestDrive/SampleDir/Child-2 -Type Directory -Force | Out-Null
New-Item $TestDrive/SampleDir/Test.txt -Type File -Force | Out-Null
$destinationPath = "$TestDrive/SampleDir/Child-*/SampleChidArchive.zip"
$sourcePath = "$TestDrive/SampleDir/Test.txt"
try
{
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
throw "Failed to detect that destination $destinationPath can resolve to multiple paths"
}
catch
{
$_.FullyQualifiedErrorId | Should Be "InvalidArchiveFilePath,Compress-Archive"
}
finally
{
Remove-Item -LiteralPath $TestDrive/SampleDir -Force -Recurse
}
}
It "Validate that Compress-Archive cmdlet works when DestinationPath has wild card pattern and resolves to a single valid path" {
New-Item $TestDrive/SampleDir/Child-1 -Type Directory -Force | Out-Null
New-Item $TestDrive/SampleDir/Test.txt -Type File -Force | Out-Null
$destinationPath = "$TestDrive/SampleDir/Child-*/SampleChidArchive.zip"
$sourcePath = "$TestDrive/SampleDir/Test.txt"
try
{
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
$destinationPath | Should Exist
}
finally
{
Remove-Item -LiteralPath $TestDrive/SampleDir -Force -Recurse
}
}
# This test requires a fix in PS5 to support reading paths with square bracket
It "Validate that Compress-Archive cmdlet can accept LiteralPath parameter for a directory with Special Characters in the directory name" -skip:($PSVersion -lt "5.0") {
$sourcePath = "$TestDrive/Source[]Dir/ChildDir[]-1"
New-Item $sourcePath -Type Directory | Out-Null
"Some Random Content" | Out-File -LiteralPath "$sourcePath/Sample[]File.txt"
$destinationPath = "$TestDrive/SampleDirWithSpecialCharacters.zip"
try
{
Compress-Archive -LiteralPath $sourcePath -DestinationPath $destinationPath
$destinationPath | Should Exist
}
finally
{
get-item -LiteralPath $sourcePath | Remove-Item -Force -Recurse
# Remove-Item -LiteralPath $sourcePath -Force -Recurse
}
}
It "Validate that Compress-Archive cmdlet can accept DestinationPath parameter with Special Characters" {
$sourcePath = "$TestDrive/SourceDir/ChildDir-1/Sample-3.txt"
$destinationPath = "$TestDrive/Sample[]SingleFile.zip"
try
{
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path -LiteralPath $destinationPath | Should Be $true
}
finally
{
Get-Item -LiteralPath $destinationPath | Remove-Item -Force
# Remove-Item -LiteralPath $destinationPath -Force
}
}
It "Validate that Source Path can be at SystemDrive location" -skip:($IsCoreCLR) {
$sourcePath = "$env:SystemDrive/SourceDir"
$destinationPath = "$TestDrive/SampleFromSystemDrive.zip"
New-Item $sourcePath -Type Directory | Out-Null
"Some Data" | Out-File -FilePath $sourcePath/SampleSourceFileForArchive.txt
try
{
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
finally
{
remove-item "$sourcePath" -Force -Recurse -ErrorAction SilentlyContinue
}
}
It "Validate that multiple files can be compressed using Compress-Archive cmdlet" {
$sourcePath = @(
"$TestDrive/SourceDir/ChildDir-1/Sample-3.txt",
"$TestDrive/SourceDir/ChildDir-1/Sample-4.txt",
"$TestDrive/SourceDir/ChildDir-2/Sample-5.txt",
"$TestDrive/SourceDir/ChildDir-2/Sample-6.txt")
$destinationPath = "$TestDrive/SampleMultipleFiles.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
It "Validate that multiple files and directories can be compressed using Compress-Archive cmdlet" {
$sourcePath = @(
"$TestDrive/SourceDir/Sample-1.txt",
"$TestDrive/SourceDir/Sample-2.txt",
"$TestDrive/SourceDir/ChildDir-1",
"$TestDrive/SourceDir/ChildDir-2")
$destinationPath = "$TestDrive/SampleMultipleFilesAndDirs.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
It "Validate that a single directory can be compressed using Compress-Archive cmdlet" {
$sourcePath = @("$TestDrive/SourceDir/ChildDir-1")
$destinationPath = "$TestDrive/SampleSingleDir.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
It "Validate that a single directory with multiple files and subdirectories can be compressed using Compress-Archive cmdlet" {
$sourcePath = @("$TestDrive/SourceDir")
$destinationPath = "$TestDrive/SampleSubTree.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
It "Validate that a single directory & multiple files can be compressed using Compress-Archive cmdlet" {
$sourcePath = @(
"$TestDrive/SourceDir/ChildDir-1",
"$TestDrive/SourceDir/Sample-1.txt",
"$TestDrive/SourceDir/Sample-2.txt")
$destinationPath = "$TestDrive/SampleMultipleFilesAndSingleDir.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
It "Validate that if .zip extension is not supplied as input to DestinationPath parameter, then .zip extension is appended" {
$sourcePath = @("$TestDrive/SourceDir")
$destinationPath = "$TestDrive/SampleNoExtension.zip"
$destinationWithoutExtensionPath = "$TestDrive/SampleNoExtension"
Compress-Archive -Path $sourcePath -DestinationPath $destinationWithoutExtensionPath
Test-Path $destinationPath | Should Be $true
}
It "Validate that -Update parameter makes Compress-Archive to not throw an error if archive file already exists" {
$sourcePath = @("$TestDrive/SourceDir")
$destinationPath = "$TestDrive/SampleUpdateTest.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath -Update
Test-Path $destinationPath | Should Be $true
}
It "Validate -Update parameter by adding a new file to an existing archive file" {
$sourcePath = @("$TestDrive/SourceDir/ChildDir-1")
$destinationPath = "$TestDrive/SampleUpdateAdd1File.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
New-Item $TestDrive/SourceDir/ChildDir-1/Sample-AddedNewFile.txt -Type File | Out-Null
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath -Update
Test-Path $destinationPath | Should Be $true
Validate-ArchiveEntryCount -path $destinationPath -expectedEntryCount 3
}
It "Validate that all CompressionLevel values can be used with Compress-Archive cmdlet" {
$sourcePath = "$TestDrive/SourceDir/Sample-1.txt"
$destinationPath = "$TestDrive/FastestCompressionLevel.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath -CompressionLevel Fastest
Test-Path $destinationPath | Should Be $true
$destinationPath = "$TestDrive/OptimalCompressionLevel.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath -CompressionLevel Optimal
Test-Path $destinationPath | Should Be $true
$destinationPath = "$TestDrive/NoCompressionCompressionLevel.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath -CompressionLevel NoCompression
Test-Path $destinationPath | Should Be $true
}
It "Validate that -Update parameter is modifying a file that already exists in the archive file" {
$filePath = "$TestDrive/SourceDir/ChildDir-1/Sample-3.txt"
$initialContent = "Initial Content"
$modifiedContent = "Modified Content"
$initialContent | Set-Content $filePath
$sourcePath = "$TestDrive/SourceDir"
$destinationPath = "$TestDrive/UpdatingModifiedFile.zip"
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $True
$modifiedContent | Set-Content $filePath
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath -Update
Test-Path $destinationPath | Should Be $True
ArchiveFileEntryContentValidator "$destinationPath" ([io.path]::Combine("SourceDir","ChildDir-1","Sample-3.txt")) $modifiedContent
}
It "Validate Compress-Archive cmdlet in pipleline scenario" {
$destinationPath = "$TestDrive/CompressArchiveFromPipeline.zip"
# Piping a single file path to Compress-Archive
dir -Path $TestDrive/SourceDir/Sample-1.txt | Compress-Archive -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $True
# Piping a string directory path to Compress-Archive
"$TestDrive/SourceDir/ChildDir-2" | Compress-Archive -DestinationPath $destinationPath -Update
Test-Path $destinationPath | Should Be $True
# Piping the output of Get-ChildItem to Compress-Archive
dir "$TestDrive/SourceDir" -Recurse | Compress-Archive -DestinationPath $destinationPath -Update
Test-Path $destinationPath | Should Be $True
}
It "Validate that Compress-Archive works on ReadOnly files" {
$sourcePath = "$TestDrive/ReadOnlyFile.txt"
$destinationPath = "$TestDrive/TestForReadOnlyFile.zip"
"Some Content" | Out-File -FilePath $sourcePath
$createdItem = Get-Item $sourcePath
$createdItem.Attributes = 'ReadOnly'
Compress-Archive -Path $sourcePath -DestinationPath $destinationPath
Test-Path $destinationPath | Should Be $true
}
It "Validate that Compress-Archive generates Verbose messages" {
$sourcePath = "$TestDrive/SourceDir"
$destinationPath = "$TestDrive/Compress-Archive generates VerboseMessages.zip"
try
{
$ps=[PowerShell]::Create()
$ps.Streams.Error.Clear()
$ps.Streams.Verbose.Clear()
$script = "Import-Module Microsoft.PowerShell.Archive; Compress-Archive -Path $sourcePath -DestinationPath `"$destinationPath`" -CompressionLevel Fastest -Verbose"
$ps.AddScript($script)
$ps.Invoke()
$ps.Streams.Verbose.Count -gt 0 | Should Be $True
$ps.Streams.Error.Count | Should Be 0
}
finally
{
$ps.Dispose()
}
}
}
Context "Expand-Archive - Parameter validation test cases" {
It "Validate non existing archive -Path trows expected error message" {
$sourcePath = "$TestDrive/SourceDir"
$destinationPath = "$TestDrive/ExpandedArchive"
try
{
Expand-Archive -Path $sourcePath -DestinationPath $destinationPath
throw "Expand-Archive succeeded for non existing archive path"
}
catch
{
$_.FullyQualifiedErrorId | Should Be "PathNotFound,Expand-Archive"
}
}
It "Validate errors from Expand-Archive with NULL & EMPTY values for Path, LiteralPath, DestinationPath parameters" {
ExpandArchiveInvalidParameterValidator $false $null "$TestDrive/SourceDir" "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $false $null $null "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $false "$TestDrive/SourceDir" $null "ParameterArgumentTransformationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $false "" "$TestDrive/SourceDir" "ParameterArgumentTransformationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $false "$TestDrive/SourceDir" "" "ParameterArgumentTransformationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $false "" "" "ParameterArgumentTransformationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true $null "$TestDrive/SourceDir" "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true $null $null "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true "$TestDrive/SourceDir" $null "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true "" "$TestDrive/SourceDir" "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true "$TestDrive/SourceDir" "" "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true "" "" "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true $null "$TestDrive/SourceDir" "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true $null $null "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true "$TestDrive/SourceDir" $null "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true "" "$TestDrive/SourceDir" "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true "$TestDrive/SourceDir" "" "ParameterArgumentValidationError,Expand-Archive"
ExpandArchiveInvalidParameterValidator $true "" "" "ParameterArgumentValidationError,Expand-Archive"
}
It "Validate errors from Expand-Archive when invalid path (non-existing path / non-filesystem path) is supplied for Path or LiteralPath parameters" {
try { Expand-Archive -Path "$TestDrive/NonExistingArchive" -DestinationPath "$TestDrive/SourceDir"; throw "Expand-Archive did NOT throw expected error" }
catch { $_.FullyQualifiedErrorId | Should Be "ArchiveCmdletPathNotFound,Expand-Archive" }
if ( ! $IsCoreCLR ) {
try { Expand-Archive -Path "HKLM:/SOFTWARE" -DestinationPath "$TestDrive/SourceDir"; throw "Expand-Archive did NOT throw expected error" }
catch { $_.FullyQualifiedErrorId | Should Be "PathNotFound,Expand-Archive" }
}
try { Expand-Archive -LiteralPath "$TestDrive/NonExistingArchive" -DestinationPath "$TestDrive/SourceDir"; throw "Expand-Archive did NOT throw expected error" }
catch { $_.FullyQualifiedErrorId | Should Be "ArchiveCmdletPathNotFound,Expand-Archive" }
if ( ! $IsCoreCLR ) {
try { Expand-Archive -LiteralPath "HKLM:/SOFTWARE" -DestinationPath "$TestDrive/SourceDir"; throw "Expand-Archive did NOT throw expected error" }
catch { $_.FullyQualifiedErrorId | Should Be "PathNotFound,Expand-Archive" }
}
}
It "Validate error from Expand-Archive when invalid path (non-existing path / non-filesystem path) is supplied for DestinationPath parameter" {
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
# $destinationPath = "HKLM:/SOFTWARE"
$destinationPath = "Variable:/"
try { Expand-Archive -Path $sourcePath -DestinationPath $destinationPath; throw "Expand-Archive did NOT throw expected error" }
catch { $_.FullyQualifiedErrorId | Should Be "InvalidDirectoryPath,Expand-Archive" }
}
}
Context "Expand-Archive - functional test cases" {
It "Validate basic Expand-Archive scenario" {
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
$content = "Some Data"
$destinationPath = "$TestDrive/DestDirForBasicExpand"
$files = @("Sample-1.txt", "Sample-2.txt")
# The files in "$TestDrive/SamplePreCreatedArchive.zip" are precreated.
$fileCreationTimeStamp = Get-Date -Year 2014 -Month 6 -Day 13 -Hour 15 -Minute 50 -Second 20 -Millisecond 0
Expand-Archive -Path $sourcePath -DestinationPath $destinationPath
foreach($currentFile in $files)
{
$expandedFile = Join-Path $destinationPath -ChildPath $currentFile
Test-Path $expandedFile | Should Be $True
# We are validating to make sure that time stamps are preserved in the
# compressed archive are reflected back when the file is expanded.
(dir $expandedFile).LastWriteTime.CompareTo($fileCreationTimeStamp) | Should Be 0
Get-Content $expandedFile | Should Be $content
}
}
It "Validate that Expand-Archive cmdlet errors out when DestinationPath resolves to multiple locations" {
$testbasename = "TargetDir"
setup -d "$testbasename"
setup -d "$testbasename/Child-1"
setup -d "$testbasename/Child-2"
$destinationPath = [io.path]::Combine("$TestDrive","$testbasename","Child-*")
$sourcePath = join-path "$TestDrive" "SamplePreCreatedArchive.zip"
try
{
Expand-Archive -Path $sourcePath -DestinationPath $destinationPath
throw "Failed to detect that destination $destinationPath can resolve to multiple paths"
}
catch
{
$_.FullyQualifiedErrorId | Should Be "InvalidDestinationPath,Expand-Archive"
}
finally
{
Remove-Item -LiteralPath "$TestDrive/$testbasename" -Force -Recurse
}
}
It "Validate that Expand-Archive cmdlet works when DestinationPath resolves has wild card pattern and resolves to a single valid path" {
$testbasename = "TargetDir"
setup -d "$testbasename"
setup -d "$testbasename/Child-1"
$destinationPath = [io.path]::Combine("$TestDrive","$testbasename","Child-*")
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
try
{
Expand-Archive -Path $sourcePath -DestinationPath $destinationPath
$expandedFiles = Get-ChildItem $destinationPath -Recurse
$expandedFiles.Length | Should BeGreaterThan 1
}
finally
{
Remove-Item -LiteralPath "$TestDrive/$testbasename" -Force -Recurse
}
}
It "Validate Expand-Archive scenario where DestinationPath has Special Characters" {
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
$content = "Some Data"
$destinationPath = "$TestDrive/DestDir[]Expand"
$files = @("Sample-1.txt", "Sample-2.txt")
# The files in "$TestDrive/SamplePreCreatedArchive.zip" are precreated.
$fileCreationTimeStamp = Get-Date -Year 2014 -Month 6 -Day 13 -Hour 15 -Minute 50 -Second 20 -Millisecond 0
Expand-Archive -Path $sourcePath -DestinationPath $destinationPath
foreach($currentFile in $files)
{
$expandedFile = Join-Path $destinationPath -ChildPath $currentFile
Test-Path -LiteralPath $expandedFile | Should Be $True
# We are validating to make sure that time stamps are preserved in the
# compressed archive are reflected back when the file is expanded.
(dir -LiteralPath $expandedFile).LastWriteTime.CompareTo($fileCreationTimeStamp) | Should Be 0
Get-Content -LiteralPath $expandedFile | Should Be $content
}
}
It "Invoke Expand-Archive with relative path in Path parameter and -Force parameter" {
$sourcePath = "./SamplePreCreatedArchive.zip"
$destinationPath = "$TestDrive/SomeOtherNonExistingDir/Path"
try
{
Push-Location $TestDrive
Expand-Archive -Path $sourcePath -DestinationPath $destinationPath -Force
$expandedFiles = Get-ChildItem $destinationPath -Recurse
$expandedFiles.Length | Should Be 2
}
finally
{
Pop-Location
}
}
It "Invoke Expand-Archive with relative path in LiteralPath parameter and -Force parameter" {
$sourcePath = "./SamplePreCreatedArchive.zip"
$destinationPath = "$TestDrive/SomeOtherNonExistingDir/LiteralPath"
try
{
Push-Location $TestDrive
Expand-Archive -LiteralPath $sourcePath -DestinationPath $destinationPath -Force
$expandedFiles = Get-ChildItem $destinationPath -Recurse
$expandedFiles.Length | Should Be 2
}
finally
{
Pop-Location
}
}
It "Invoke Expand-Archive with non-existing relative directory in DestinationPath parameter and -Force parameter" {
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
$destinationPath = "./SomeOtherNonExistingDir/DestinationPath"
try
{
Push-Location $TestDrive
Expand-Archive -Path $sourcePath -DestinationPath $destinationPath -Force
$expandedFiles = Get-ChildItem $destinationPath -Recurse
$expandedFiles.Length | Should Be 2
}
finally
{
Pop-Location
}
}
It "Invoke Expand-Archive with unsupported archive format" {
$sourcePath = "$TestDrive/Sample.cab"
$destinationPath = "$TestDrive/UnsupportedArchiveFormatDir"
try
{
Expand-Archive -Path $sourcePath -DestinationPath $destinationPath -Force
throw "Failed to detect unsupported archive format at $sourcePath"
}
catch
{
$_.FullyQualifiedErrorId | Should Be "NotSupportedArchiveFileExtension,Expand-Archive"
}
}
It "Invoke Expand-Archive with archive file containing multiple files, directories with subdirectories and empty directories" {
$sourcePath = "$TestDrive/SourceDir"
$archivePath = "$TestDrive/FileAndDirTreeForExpand.zip"
$destinationPath = "$TestDrive/FileAndDirTree"
$sourceList = dir $sourcePath -Name
Add-CompressionAssemblies
[System.IO.Compression.ZipFile]::CreateFromDirectory($sourcePath, $archivePath)
Expand-Archive -Path $archivePath -DestinationPath $destinationPath
$extractedList = dir $destinationPath -Name
Compare-Object -ReferenceObject $extractedList -DifferenceObject $sourceList -PassThru | Should Be $null
}
It "Validate Expand-Archive cmdlet in pipleline scenario" {
$sourcePath = "$TestDrive/SamplePreCreated*.zip"
$destinationPath = "$TestDrive/PipeToExpandArchive"
$content = "Some Data"
$files = @("Sample-1.txt", "Sample-2.txt")
dir $sourcePath | Expand-Archive -DestinationPath $destinationPath
foreach($currentFile in $files)
{
$expandedFile = Join-Path $destinationPath -ChildPath $currentFile
Test-Path $expandedFile | Should Be $True
Get-Content $expandedFile | Should Be $content
}
}
It "Validate that Expand-Archive generates Verbose messages" {
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
$destinationPath = "$TestDrive/VerboseMessagesInExpandArchive"
try
{
$ps=[PowerShell]::Create()
$ps.Streams.Error.Clear()
$ps.Streams.Verbose.Clear()
$script = "Import-Module Microsoft.PowerShell.Archive; Expand-Archive -Path $sourcePath -DestinationPath $destinationPath -Verbose"
$ps.AddScript($script)
$ps.Invoke()
$ps.Streams.Verbose.Count -gt 0 | Should Be $True
$ps.Streams.Error.Count | Should Be 0
}
finally
{
$ps.Dispose()
}
}
It "Validate that without -Force parameter Expand-Archive generates non-terminating errors without overwriting existing files" {
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
$destinationPath = "$TestDrive/NoForceParameterExpandArchive"
try
{
$ps=[PowerShell]::Create()
$ps.Streams.Error.Clear()
$ps.Streams.Verbose.Clear()
$script = "Import-Module Microsoft.PowerShell.Archive; Expand-Archive -Path $sourcePath -DestinationPath $destinationPath; Expand-Archive -Path $sourcePath -DestinationPath $destinationPath"
$ps.AddScript($script)
$ps.Invoke()
$ps.Streams.Error.Count -gt 0 | Should Be $True
}
finally
{
$ps.Dispose()
}
}
It "Validate that without DestinationPath parameter Expand-Archive cmdlet succeeds in expanding the archive" {
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
$archivePath = "$TestDrive/NoDestinationPathParameter.zip"
$destinationPath = "$TestDrive/NoDestinationPathParameter"
copy-item $sourcePath $archivePath -Force
try
{
Push-Location $TestDrive
Expand-Archive -Path $archivePath
(dir $destinationPath).Count | Should Be 2
}
finally
{
Pop-Location
}
}
It "Validate that without DestinationPath parameter Expand-Archive cmdlet succeeds in expanding the archive when destination directory exists" {
$sourcePath = "$TestDrive/SamplePreCreatedArchive.zip"
$archivePath = "$TestDrive/NoDestinationPathParameterDirExists.zip"
$destinationPath = "$TestDrive/NoDestinationPathParameterDirExists"
copy-item $sourcePath $archivePath -Force
New-Item -Path $destinationPath -ItemType Directory | Out-Null
try
{
Push-Location $TestDrive
Expand-Archive -Path $archivePath
(dir $destinationPath).Count | Should Be 2
}
finally
{
Pop-Location
}
}
}
}

View file

@ -0,0 +1,64 @@
Describe "History cmdlet test cases" -Tags "CI" {
It "Tests Invoke-History on a cmdlet that generates output on all streams" {
$streamSpammer = '
function StreamSpammer
{
[CmdletBinding()]
param()
Write-Debug "Debug"
Write-Error "Error"
Write-Information "Information"
Write-Progress "Progress"
Write-Verbose "Verbose"
Write-Warning "Warning"
"Output"
}
$informationPreference = "Continue"
$debugPreference = "Continue"
$verbosePreference = "Continue"
'
$invocationSettings = New-Object System.Management.Automation.PSInvocationSettings
$invocationSettings.AddToHistory = $true
$ps = [PowerShell]::Create()
$null = $ps.AddScript($streamSpammer).Invoke()
$ps.Commands.Clear()
$null = $ps.AddScript("StreamSpammer");
$null = $ps.Invoke($null, $invocationSettings)
$ps.Commands.Clear()
$null = $ps.AddScript("Invoke-History -id 1")
$result = $ps.Invoke($null, $invocationSettings)
$outputCount = $(
$ps.Streams.Error;
$ps.Streams.Progress;
$ps.Streams.Verbose;
$ps.Streams.Debug;
$ps.Streams.Warning;
$ps.Streams.Information).Count
$ps.Dispose()
## Twice per stream - once for the original invocatgion, and once for the re-invocation
$outputCount | Should be 12
}
It "Tests Invoke-History on a private command" {
$invocationSettings = New-Object System.Management.Automation.PSInvocationSettings
$invocationSettings.AddToHistory = $true
$ps = [PowerShell]::Create()
$null = $ps.AddScript("(Get-Command Get-Process).Visibility = 'Private'").Invoke()
$ps.Commands.Clear()
$null = $ps.AddScript("Get-Process -id $pid")
$null = $ps.Invoke($null, $invocationSettings)
$ps.Commands.Clear()
$null = $ps.AddScript("Invoke-History -id 1")
$result = $ps.Invoke($null, $invocationSettings)
$errorResult = $ps.Streams.Error[0].FullyQualifiedErrorId
$ps.Dispose()
$errorResult | Should be CommandNotFoundException
}
}

View file

@ -0,0 +1,52 @@
##
## Copyright (c) Microsoft Corporation, 2015
##
Describe "Tests Get-Command with relative paths and wildcards" -Tag "CI" {
BeforeAll {
# Create temporary EXE command files
$file1 = Setup -f WildCardCommandA.exe -pass
$file2 = Setup -f WildCardCommand[B].exe -pass
#$null = New-Item -ItemType File -Path (Join-Path $TestDrive WildCardCommandA.exe) -ErrorAction Ignore
#$null = New-Item -ItemType File -Path (Join-Path $TestDRive WildCardCommand[B].exe) -ErrorAction Ignore
if ( $IsLinux -or $IsOSX ) {
/bin/chmod 777 "$file1"
/bin/chmod 777 "$file2"
}
}
It "Test wildcard with drive relative directory path" {
$pathName = Join-Path $TestDrive "WildCardCommandA*"
$driveOffset = $pathName.IndexOf(":")
$pathName = $pathName.Substring($driveOffset + 1)
$result = Get-Command -Name $pathName
$result | Should Not Be $null
$result.Name | Should Be WildCardCommandA.exe
}
It "Test wildcard with relative directory path" {
push-location $TestDrive
$result = Get-Command -Name .\WildCardCommandA*
pop-location
$result | Should Not Be $null
$result | Should Be WildCardCommandA.exe
}
It "Test with PowerShell wildcard and relative path" {
push-location $TestDrive
# This should use the wildcard to find WildCardCommandA.exe
$result = Get-Command -Name .\WildCardCommand[A].exe
$result | Should Not Be $null
$result | Should Be WildCardCommandA.exe
# This should find the file WildCardCommand[B].exe
$result = Get-Command -Name .\WildCardCommand[B].exe
$result | Should Not Be $null
$result | Should Be WildCardCommand[B].exe
Pop-Location
}
}

View file

@ -0,0 +1,868 @@
# This is a Pester test suite to validate Copy-Item remotely using a remote session.
#
# Copyright (c) Microsoft Corporation, 2015
#
#
# If PS Remoting is not available, do not run the suite.
function ShouldRun
{
if ( $IsCoreCLR ) { return $false }
$result = Invoke-Command -ComputerName . -ScriptBlock {1} -ErrorAction SilentlyContinue
return ($result -eq 1)
}
if (-not (ShouldRun))
{
Write-Host "PS Remoting is not available, skipping tests..." -ForegroundColor Cyan
return
}
Describe "Validate Copy-Item Remotely" -Tags "CI" {
# Validate a copy item operation.
# $filePath is the source file path
#
function ValidateCopyItemOperation
{
param ([string]$filePath, [string]$destination)
if (-not $destination)
{
$copiedFilePath = ([string]$filePath).Replace("SourceDirectory", "DestinationDirectory")
}
else
{
$fileName = Split-Path $filePath -Leaf
$copiedFilePath = Join-Path $destination $fileName
}
$copiedFilePath | should Exist
# Validate file attributes
$originalFile = Get-Item $filePath -Force
$newFile = Get-Item $copiedFilePath -Force
# Validate file Length
$newFile.Length | should be $originalFile.Length
# Validate LastWriteTime
$newFile.LastWriteTime | should be $originalFile.LastWriteTime
$newFile.LastWriteTimeUtc | should be $originalFile.LastWriteTimeUtc
# Validate Attributes
$newFile.Attributes.value__ | Should Be $originalFile.Attributes.value__
}
# Validate a copy item operation.
# $filePath is the source file path
#
function ValidateCopyItemOperationForAlternateDataStream
{
param ([string]$filePath, $streamName, $expectedStreamContent)
$copiedFilePath = ([string]$filePath).Replace("SourceDirectory", "DestinationDirectory")
$copiedFilePath | should Exist
(Get-Item $copiedFilePath).Length | should be (Get-Item $filePath).Length
# Validate the stream
$actualStreamContent = Get-Content -Path $copiedFilePath -Stream $streamName -ea SilentlyContinue
$actualStreamContent | Should Match $expectedStreamContent
}
BeforeAll {
$s = New-PSSession -ComputerName . -ea SilentlyContinue
if (-not $s)
{
throw "Failed to create PSSession for remote copy operations."
}
$destinationFolderName = "DestinationDirectory"
$sourceFolderName = "SourceDirectory"
$testDirectory = Join-Path "TestDrive:" "copyItemRemotely"
$destinationDirectory = Join-Path $testDirectory $destinationFolderName
$sourceDirectory = Join-Path $testDirectory $sourceFolderName
# Creates one txt file
#
function CreateTestFile
{
param ([switch]$setReadOnlyAttribute = $false, [switch]$emptyFile = $false)
# Create the test directory.
New-Item -Path $sourceDirectory -Force -ItemType Directory | Out-Null
# Create the file.
$filePath = Join-Path $sourceDirectory "testfileone.txt"
if (-not $emptyFile)
{
"File test content" | Out-File $filePath -Force
}
else
{
"" | Out-File $filePath -Force
}
if (-not (Test-Path $filePath))
{
throw "Failed to create test file $filePath."
}
if ($setReadOnlyAttribute)
{
Set-ItemProperty $filePath -Name IsReadOnly -value $true -Force
}
return (Get-Item $filePath).FullName
}
# Create a set of directories and files with the following structure:
# .\copyItemRemotely\SourceDirectory\A\a.txt
# .\copyItemRemotely\SourceDirectory\A\a2.txt
# .\copyItemRemotely\SourceDirectory\rootFile.txt
# .\copyItemRemotely\SourceDirectory\B\b.txt
# .\copyItemRemotely\SourceDirectory\C\D\d.txt
#
function CreateTestDirectory
{
param ([switch]$setReadOnlyAttribute = $false)
$directoriesToCreate = @()
$directoriesToCreate += "A"
$directoriesToCreate += "B"
$directoriesToCreate += "C\D"
$filesToCreate = @()
$filesToCreate += "rootFile.txt"
$filesToCreate += "A\a.txt"
$filesToCreate += "A\a2.txt"
$filesToCreate += "B\b.txt"
$filesToCreate += "C\D\d.txt"
# Create the directories.
foreach ($directory in $directoriesToCreate)
{
$directoryPath = Join-Path $sourceDirectory $directory
New-Item -Path $directoryPath -Force -ItemType Directory | Out-Null
}
$result = @{
SourceDirectory = (Get-Item $sourceDirectory).FullName
Files = @()
}
# Create the files.
foreach ($file in $filesToCreate)
{
$filePath = Join-Path $sourceDirectory $file
$file + "`r`n File test content" | Out-File $filePath -Force
if (-not (Test-Path $filePath))
{
throw "Failed to create test file $filePath."
}
if ($setReadOnlyAttribute)
{
Set-ItemProperty $filePath -Name IsReadOnly -value $true -Force
}
$result.Files += (Get-Item $filePath).FullName
}
return $result
}
function GenerateTestAssembly
{
$assemblyPath = Join-Path $env:TEMP TestModule
$outputPath = Join-Path $assemblyPath TestModule.dll
if (-not (Test-Path $assemblyPath))
{
New-Item $assemblyPath -Force -ItemType Directory | Out-Null
}
if (-not (Test-Path $outputPath))
{
$code = @"
namespace TestModule
{
using System;
using System.Management.Automation;
[Cmdlet(VerbsCommon.Get, "TestModule")]
public class TestSameCmdlets : PSCmdlet
{
protected override void ProcessRecord()
{
WriteObject("TestModule");
}
}
}
"@
Add-Type -TypeDefinition $code -OutputAssembly $outputPath
}
$result = @{
ModuleName = "TestModule"
Path = (Get-Item $outputPath).FullName
}
return $result
}
function GetDestinationFolderPath
{
return (Get-Item $destinationDirectory).FullName
}
}
AfterAll {
Remove-PSSession -Name $s.Name -ea SilentlyContinue
}
BeforeEach {
<# Ensure we start with an empty test directory. Here is the file structure
$destinationFolderName = "DestinationDirectory"
$sourceFolderName = "SourceDirectory"
$testDirectory = Join-Path "TestDrive:" "copyItemRemotely"
$destinationDirectory = Join-Path $testDirectory $destinationFolderName
$sourceDirectory = Join-Path $testDirectory $sourceFolderName
#>
if (test-path $testDirectory)
{
Remove-Item $testDirectory -Force -ea SilentlyContinue -Recurse
}
# Create testDirectory, and destinationDirectory
New-Item $testDirectory -ItemType Directory -Force | Out-Null
New-Item $destinationDirectory -ItemType Directory -Force | Out-Null
}
Context "Validate Copy-Item Locally." {
It "Copy-Item -Path $filePath -Destination $destinationFolderPath" {
$filePath = CreateTestFile
$destinationFolderPath = GetDestinationFolderPath
Copy-Item -Path $filePath -Destination $destinationFolderPath
ValidateCopyItemOperation -filePath $filePath
}
It "Copy-Item -Path $($testObject.SourceDirectory) -Destination $destinationFolderPath -Recurse" {
$testObject = CreateTestDirectory
$destinationFolderPath = GetDestinationFolderPath
Copy-Item -Path $testObject.SourceDirectory -Destination $destinationFolderPath -Recurse
foreach ($file in $testObject.Files)
{
$copiedFilePath = ([string]$file).Replace("SourceDirectory", "DestinationDirectory\SourceDirectory")
$copiedFilePath | should Exist
}
}
}
Context "Validate Copy-Item to remote session." {
It "Copy one file to remote session." {
$filePath = CreateTestFile
$destinationFolderPath = GetDestinationFolderPath
Copy-Item -Path $filePath -ToSession $s -Destination $destinationFolderPath
ValidateCopyItemOperation -filePath $filePath
}
It "Copy one read only file to remote session." {
$filePath = CreateTestFile -setReadOnlyAttribute
$destinationFolderPath = GetDestinationFolderPath
Copy-Item -Path $filePath -ToSession $s -Destination $destinationFolderPath -Force
ValidateCopyItemOperation -filePath $filePath
}
It "Copy-Item works for a read only file when '-Force' is not used." {
$filePath = CreateTestFile -setReadOnlyAttribute
$destinationFolderPath = GetDestinationFolderPath
Copy-Item -Path $filePath -ToSession $s -Destination $destinationFolderPath -Verbose
ValidateCopyItemOperation -filePath $filePath
}
It "Copy one folder to session Recursively" {
$testObject = CreateTestDirectory
$destinationFolderPath = GetDestinationFolderPath
Copy-Item -Path $testObject.SourceDirectory -ToSession $s -Destination $destinationFolderPath -Recurse
foreach ($file in $testObject.Files)
{
$copiedFilePath = ([string]$file).Replace("SourceDirectory", "DestinationDirectory\SourceDirectory")
$copiedFilePath | should Exist
(Get-Item $copiedFilePath).Length | should be (Get-Item $file).Length
}
}
It "Copy folder with read only files to remote session recursively." {
$testObject = CreateTestDirectory -setReadOnlyAttribute
$destinationFolderPath = GetDestinationFolderPath
Copy-Item -Path $testObject.SourceDirectory -ToSession $s -Destination $destinationFolderPath -Recurse -Force
foreach ($file in $testObject.Files)
{
$copiedFilePath = ([string]$file).Replace("SourceDirectory", "DestinationDirectory\SourceDirectory")
$copiedFilePath | should Exist
(Get-Item $copiedFilePath).Length | should be (Get-Item $file).Length
}
}
It "Copy one file to remote session fails when the remote directory does not exist." {
$filePath = CreateTestFile
$destinationFolderPath = GetDestinationFolderPath
$destinationFolderPath = Join-Path $destinationFolderPath "A\B\C\D\E"
$expectedFullyQualifiedErrorId = 'RemotePathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand'
try
{
Copy-Item -Path $filePath -ToSession $s -Destination $destinationFolderPath -ErrorAction Stop
throw "CodeExecuted"
}
catch
{
$_.FullyQualifiedErrorId | should be $expectedFullyQualifiedErrorId
}
}
It "Copy folder to remote session recursively works even if the target directory does not exist." {
$testObject = CreateTestDirectory -setReadOnlyAttribute
$destinationFolderPath = GetDestinationFolderPath
$destinationFolderPath = Join-Path $destinationFolderPath "FoderThatDoesNotExist"
Copy-Item -Path $testObject.SourceDirectory -ToSession $s -Destination $destinationFolderPath -Recurse -Force
foreach ($file in $testObject.Files)
{
$copiedFilePath = ([string]$file).Replace("SourceDirectory", "DestinationDirectory\FoderThatDoesNotExist")
$copiedFilePath | should Exist
(Get-Item $copiedFilePath).Length | should be (Get-Item $file).Length
}
}
It "Copy one empty file to remote session." {
$filePath = CreateTestFile -emptyFile
$destinationFolderPath = GetDestinationFolderPath
$copiedFilePath = ([string]$filePath).Replace("SourceDirectory", "DestinationDirectory")
$copiedFilePath | should Not Exist
Copy-Item -Path $filePath -ToSession $s -Destination $destinationFolderPath
$copiedFilePath | should Exist
(Get-Item $copiedFilePath).Length | should be (Get-Item $filePath).Length
}
It "Copy-Item to session supports alternate data streams." {
$filePath = CreateTestFile
$destinationFolderPath = GetDestinationFolderPath
$streamContent = "This content is hidden"
$streamName = "Hidden"
Set-Content -Path $filePath -Value $streamContent -Stream $streamName
Copy-Item -Path $filePath -ToSession $s -Destination $destinationFolderPath -Verbose
ValidateCopyItemOperationForAlternateDataStream -filePath $filePath -streamName $streamName -expectedStreamContent $streamContent
}
}
Context "Validate Copy-Item from remote session." {
It "Copy one file from remote session." {
$filePath = CreateTestFile
$destinationFolderPath = GetDestinationFolderPath
$copiedFilePath = ([string]$filePath).Replace("SourceDirectory", "DestinationDirectory")
$copiedFilePath | should Not Exist
Copy-Item -Path $filePath -FromSession $s -Destination $destinationFolderPath
ValidateCopyItemOperation -filePath $filePath
}
It "Copy one empty file from remote session." {
$filePath = CreateTestFile -emptyFile
$destinationFolderPath = GetDestinationFolderPath
$copiedFilePath = ([string]$filePath).Replace("SourceDirectory", "DestinationDirectory")
$copiedFilePath | should Not Exist
Copy-Item -Path $filePath -FromSession $s -Destination $destinationFolderPath
ValidateCopyItemOperation -filePath $filePath
}
It "Copy folder from remote session recursively." {
$testObject = CreateTestDirectory
$destinationFolderPath = GetDestinationFolderPath
$files = @(Get-ChildItem $destinationFolderPath -Recurse -Force)
Copy-Item -Path $testObject.SourceDirectory -FromSession $s -Destination $destinationFolderPath -Recurse
foreach ($file in $testObject.Files)
{
$copiedFilePath = ([string]$file).Replace("SourceDirectory", "DestinationDirectory\SourceDirectory")
$copiedFilePath | should Exist
(Get-Item $copiedFilePath).Length | should be (Get-Item $file).Length
}
}
It "Copy one file from remote session fails when the target directory does not exist." {
$filePath = CreateTestFile
$destinationFolderPath = GetDestinationFolderPath
$destinationFolderPath = Join-Path $destinationFolderPath "A\B\C\D\E"
$expectedFullyQualifiedErrorId = 'CopyItemRemotelyIOError,Microsoft.PowerShell.Commands.CopyItemCommand'
try
{
Copy-Item -Path $filePath -FromSession $s -Destination $destinationFolderPath -ErrorAction Stop
throw "CodeExecuted"
}
catch
{
$_.FullyQualifiedErrorId | should be $expectedFullyQualifiedErrorId
}
}
It "Copy folder from remote session recursively works even if the target directory does not exist." {
$testObject = CreateTestDirectory
$destinationFolderPath = GetDestinationFolderPath
$destinationFolderPath = Join-Path $destinationFolderPath "FoderThatDoesNotExist"
$files = @(Get-ChildItem $destinationFolderPath -Recurse -Force)
Copy-Item -Path $testObject.SourceDirectory -FromSession $s -Destination $destinationFolderPath -Recurse
foreach ($file in $testObject.Files)
{
$copiedFilePath = ([string]$file).Replace("SourceDirectory", "DestinationDirectory\FoderThatDoesNotExist")
$copiedFilePath | should Exist
(Get-Item $copiedFilePath).Length | should be (Get-Item $file).Length
}
}
It "Copy a read only file from a remote session." {
$filePath = CreateTestFile -setReadOnlyAttribute
$destinationFolderPath = GetDestinationFolderPath
$copiedFilePath = ([string]$filePath).Replace("SourceDirectory", "DestinationDirectory")
Copy-Item -Path $filePath -FromSession $s -Destination $destinationFolderPath -Force
ValidateCopyItemOperation -filePath $filePath
}
It "Copy-Item for a read only file works with no '-force' parameter." {
$filePath = CreateTestFile -setReadOnlyAttribute
$destinationFolderPath = GetDestinationFolderPath
Copy-Item -Path $filePath -FromSession $s -Destination $destinationFolderPath
ValidateCopyItemOperation -filePath $filePath
}
It "Copy-Item -FromSession works even when trying to copy an assembly that is currently being used by another process." {
$testAssembly = GenerateTestAssembly
$destinationFolderPath = GetDestinationFolderPath
Import-Module $testAssembly.Path -Force
try
{
Copy-Item -Path $testAssembly.Path -FromSession $s -Destination $destinationFolderPath
ValidateCopyItemOperation -filePath $testAssembly.Path
}
finally
{
Remove-Module $testAssembly.ModuleName -Force -ea SilentlyContinue
}
}
It "Copy-Item from session supports alternate data streams." {
$filePath = CreateTestFile
$destinationFolderPath = GetDestinationFolderPath
$streamContent = "This content is hidden"
$streamName = "Hidden"
Set-Content -Path $filePath -Value $streamContent -Stream $streamName
Copy-Item -Path $filePath -FromSession $s -Destination $destinationFolderPath
ValidateCopyItemOperationForAlternateDataStream -filePath $filePath -streamName $streamName -expectedStreamContent $streamContent
}
}
Context "Validate Copy-Item Remotely using wildcards" {
It "Copy-Item from session using wildcards." {
$testObject = CreateTestDirectory
$destinationFolderPath = GetDestinationFolderPath
$sourcePathWithWildcards = "$($testObject.SourceDirectory)\A\*.txt"
Copy-Item -Path $sourcePathWithWildcards -FromSession $s -Destination $destinationFolderPath -Force
$sourceFiles = @(Get-Item $sourcePathWithWildcards)
foreach ($file in $sourceFiles)
{
$copiedFilePath = Join-Path $destinationFolderPath (Split-Path $file -Leaf)
$copiedFilePath | Should Exist
(Get-Item $copiedFilePath).Length | Should Be (Get-Item $file).Length
}
}
It "Copy-Item to session using wildcards." {
$testObject = CreateTestDirectory
$destinationFolderPath = GetDestinationFolderPath
$sourcePathWithWildcards = "$($testObject.SourceDirectory)\A\*.txt"
Copy-Item -Path $sourcePathWithWildcards -ToSession $s -Destination $destinationFolderPath -Force
$sourceFiles = @(Get-Item $sourcePathWithWildcards)
foreach ($file in $sourceFiles)
{
$copiedFilePath = Join-Path $destinationFolderPath (Split-Path $file -Leaf)
$copiedFilePath | Should Exist
(Get-Item $copiedFilePath).Length | Should Be (Get-Item $file).Length
}
}
}
Context "Validate FullyQualifiedErrorIds for remote source and destination paths." {
BeforeAll {
# Create test file.
$testFilePath = Join-Path "TestDrive:" "testfile.txt"
if (test-path $testFilePath)
{
Remove-Item $testFilePath -Force -ea SilentlyContinue
}
"File test content" | Out-File $testFilePath -Force
}
function Test-CopyItemError
{
param ($path, $destination, $expectedFullyQualifiedErrorId, $fromSession = $false)
if ($fromSession)
{
It "Copy-Item FromSession -Path '$path' throws $expectedFullyQualifiedErrorId" {
try
{
Copy-Item -Path $path -FromSession $s -Destination $destination -ErrorAction Stop
throw "CodeExecuted"
}
catch
{
$_.FullyQualifiedErrorId | should be $expectedFullyQualifiedErrorId
}
}
}
else
{
It "Copy-Item ToSession -Destination '$path' throws $expectedFullyQualifiedErrorId" {
try
{
Copy-Item -Path $path -ToSession $s -Destination $destination -ErrorAction Stop
throw "CodeExecuted"
}
catch
{
$_.FullyQualifiedErrorId | should be $expectedFullyQualifiedErrorId
}
}
}
}
$invalidSourcePathtestCases = @(
@{
Path = "HKLM:\SOFTWARE"
Destination = $env:SystemDrive
ExpectedFullyQualifiedErrorId = "NamedParameterNotFound,Microsoft.PowerShell.Commands.CopyItemCommand"
FromSession = $true
}
@{
Path = ".\Source"
Destination = $env:SystemDrive
ExpectedFullyQualifiedErrorId = "RemotePathIsNotAbsolute,Microsoft.PowerShell.Commands.CopyItemCommand"
FromSession = $true
}
@{
Path = $env:SystemDrive + "\X\Y\Z"
Destination = $env:SystemDrive + "\A\B\C"
ExpectedFullyQualifiedErrorId = "RemotePathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand"
FromSession = $true
}
@{
Path = $null
Destination = $env:SystemDrive
ExpectedFullyQualifiedErrorId = "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CopyItemCommand"
FromSession = $true
}
@{
Path = ''
Destination = $env:SystemDrive
ExpectedFullyQualifiedErrorId = "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.CopyItemCommand"
FromSession = $true
}
@{
Path = "$env:SystemDrive\nonexistdir\*"
Destination = "$env:SystemDrive\psTest"
ExpectedFullyQualifiedErrorId = "RemotePathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand"
FromSession = $true
}
)
foreach ($testCase in $invalidSourcePathtestCases) {
Test-CopyItemError @testCase
}
$invalidDestinationPathtestCases = @(
@{
Path = $testFilePath
Destination = ".\Source"
ExpectedFullyQualifiedErrorId = "RemotePathIsNotAbsolute,Microsoft.PowerShell.Commands.CopyItemCommand"
}
@{
Path = $testFilePath
Destination = $env:SystemDrive + "\X\A\B\C"
ExpectedFullyQualifiedErrorId = "RemotePathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand"
}
@{
Path = $testFilePath
Destination = $null
ExpectedFullyQualifiedErrorId = "CopyItemRemoteDestinationIsNullOrEmpty,Microsoft.PowerShell.Commands.CopyItemCommand"
}
@{
Path = $testFilePath
Destination = ""
ExpectedFullyQualifiedErrorId = "CopyItemRemoteDestinationIsNullOrEmpty,Microsoft.PowerShell.Commands.CopyItemCommand"
}
@{
Path = "$env:SystemDrive\nonexistdir\*"
Destination = "$env:SystemDrive\psTest"
ExpectedFullyQualifiedErrorId = "PathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand"
}
)
foreach ($testCase in $invalidDestinationPathtestCases) {
Test-CopyItemError @testCase
}
}
}
Describe "Validate Copy-Item error for target sessions not in FullLanguageMode." -Tags "Feature" {
BeforeAll {
$testDirectory = "TestDrive:\"
# Create the test file and directories.
$source = "$testDirectory\Source"
$destination = "$testDirectory\Destination"
New-Item $source -ItemType Directory -Force | Out-Null
New-Item $destination -ItemType Directory -Force | Out-Null
$testFilePath = Join-Path $source "testfile.txt"
"File test content" | Out-File $testFilePath -Force
# Keep track of the sessions.
$testSessions = @{}
# Keep track of the session names to be unregistered.
$sessionToUnregister = @()
$languageModes = @("ConstrainedLanguage", "NoLanguage", "RestrictedLanguage")
$id = (Get-Random).ToString()
foreach ($languageMode in $languageModes)
{
$sessionName = $languageMode + "_" + $id
$sessionToUnregister += $sessionName
$configFilePath = Join-Path $testDirectory "test.pssc"
# Create the session.
Write-Host "Creating pssession with '$languageMode' ..."
New-PSSessionConfigurationFile -Path $configFilePath -SessionType Default -LanguageMode $languageMode
Register-PSSessionConfiguration -Name $sessionName -Path $configFilePath -Force | Out-Null
$testSession = New-PSSession -ConfigurationName $sessionName
# Validate that the session is opened.
$testSession.State | Should Be "Opened"
# Add the new session to the list.
$testSessions[$languageMode] = $testSession
# Remove the pssc file.
Remove-Item $configFilePath -Force -ea SilentlyContinue
}
}
AfterAll {
$testSessions.Values | Remove-PSSession -ea SilentlyContinue
$sessionToUnregister | foreach {
Unregister-PSSessionConfiguration -Name $_ -Force -ea SilentlyContinue
}
}
foreach ($languageMode in $testSessions.Keys)
{
$session = $testSessions[$languageMode]
It "Copy-Item throws 'SessionIsNotInFullLanguageMode' error for a session in '$languageMode'" {
# FromSession
try
{
Copy-Item -Path $testFilePath -FromSession $session -Destination $destination -Force -Verbose -ea Stop
throw "CodeExecuted"
}
catch
{
$_.FullyQualifiedErrorId | should be "SessionIsNotInFullLanguageMode,Microsoft.PowerShell.Commands.CopyItemCommand"
}
# ToSession
try
{
Copy-Item -Path $testFilePath -ToSession $session -Destination $destination -Force -Verbose -ea Stop
throw "CodeExecuted"
}
catch
{
$_.FullyQualifiedErrorId | should be "SessionIsNotInFullLanguageMode,Microsoft.PowerShell.Commands.CopyItemCommand"
}
}
}
}
Describe "Copy-Item can use Recurse and Exclude together" -Tags "Feature" {
Context "Local and Remote Tests" {
BeforeAll {
$s = New-PSSession -ComputerName . -ea SilentlyContinue
if (-not $s)
{
throw "Failed to create PSSession for remote copy operations."
}
$null = New-Item -ItemType Directory -Path "TestDrive:\Parent\Sub"
$null = New-Item -Path "TestDrive:\Parent\p1.txt" -Value "test"
$null = New-Item -Path "TestDrive:\Parent\p2.txt" -Value "test"
$null = New-Item -Path "TestDrive:\Parent\s4.txt" -Value "test"
$null = New-Item -Path "TestDrive:\Parent\Sub\s1.txt" -Value "test"
$null = New-Item -Path "TestDrive:\Parent\Sub\s2.txt" -Value "test"
$null = New-Item -Path "TestDrive:\Parent\Sub\s3.txt" -Value "test"
$null = New-Item -Path "TestDrive:\Parent\Sub\p3.txt" -Value "testcl"
}
It "can exclude files at sub directory" {
Copy-Item -Path TestDrive:\Parent\* -Recurse -Exclude s*.txt -Destination TestDrive:\Temp -Force
$copiedFiles = Get-ChildItem -Recurse -Path TestDrive:\Temp
$copiedFiles.Count | Should Be 3
}
It "can exclude files at sub directory to a session" {
Copy-Item -Path TestDrive:\Parent\* -Recurse -Exclude s*.txt -Destination $TestDrive\Temp2 -Force -ToSession $s
$copiedFiles = Get-ChildItem -Recurse -Path TestDrive:\Temp
$copiedFiles.Count | Should Be 3
}
It "can exclude files at sub directory from a session" {
Copy-Item -Path $TestDrive\Parent\* -Recurse -Exclude s*.txt -Destination TestDrive:\Temp3 -FromSession $s
$copiedFiles = Get-ChildItem -Recurse -Path TestDrive:\Temp2
$copiedFiles.Count | Should Be 3
}
AfterAll {
Remove-PSSession -Session $s -ErrorAction SilentlyContinue
}
}
}
Describe "Copy-Item remotely bug fixes" -Tags "Feature" {
BeforeAll {
$s = New-PSSession -ComputerName . -ErrorAction SilentlyContinue
if (-not $s)
{
throw "Failed to create PSSession for remote copy operations."
}
$originalContent = "test file 1 - Source"
$newContent = "This is some new content"
$null = New-Item -ItemType Directory -Path "TestDrive:\Source"
$null = New-Item -ItemType Directory -Path "TestDrive:\Destination"
}
AfterAll {
Remove-PSSession -Session $s -ErrorAction SilentlyContinue
}
BeforeEach {
# Create the same file in the source and destination
Set-Content -Path "TestDrive:\Source\testFile1.txt" -Value $originalContent -Force
Set-Content -Path "TestDrive:\Destination\testFile1.txt" -Value $originalContent -Force
}
Context "Copy-Item remotely overwrites a destination file if it exists." {
BeforeEach {
# Overwrite the source file
Set-Content -Path "TestDrive:\Source\testFile1.txt" -Value $newContent
}
It "Copy item -tosession overwrites the content of an existing file." {
# Copy file to session
Copy-Item -Path "TestDrive:\Source\testFile1.txt" -Destination "$TestDrive\Destination\testFile1.txt" -ToSession $s
# Validate the the file was overwritten
$fileContent = Get-Content "TestDrive:\Destination\testFile1.txt" -ea SilentlyContinue -Raw
$fileContent | Should Match $newContent
}
It "Copy item -fromsession overwrites the content of an existing file." {
# Copy file to session
Copy-Item -Path "$TestDrive\Source\testFile1.txt" -Destination "TestDrive:\Destination\testFile1.txt" -FromSession $s
# Validate the the file was overwritten
$fileContent = Get-Content "TestDrive:\Destination\testFile1.txt" -ea SilentlyContinue -Raw
$fileContent | Should Match $newContent
}
}
Context "Copy-Item remotely creates a destination file if it does not exist." {
BeforeEach {
if (Test-Path "TestDrive:\AnotherDestination")
{
Remove-Item "TestDrive:\AnotherDestination" -Force -Recurse -ea SilentlyContinue
}
$null = New-Item -ItemType Directory -Path "TestDrive:\AnotherDestination"
# Ensure the file does not exist
"TestDrive:\AnotherDestination\FileThatDoesNotExist.txt" | Should Not Exist
}
It "Copy-Item -tosession creates the file if it does not exist on the remote destination." {
# Copy file to session
Copy-Item -Path "TestDrive:\Source\testFile1.txt" -Destination "$TestDrive\AnotherDestination\FileThatDoesNotExist.txt" -ToSession $s
# Verify that the file was created
"TestDrive:\AnotherDestination\FileThatDoesNotExist.txt" | Should Exist
}
It "Copy-Item -fromsession creates the file if it does not exist on the local machine." {
# Copy file from session
Copy-Item -Path "$TestDrive\Source\testFile1.txt" -Destination "TestDrive:\AnotherDestination\FileThatDoesNotExist.txt" -FromSession $s
# Verify that the file was created
"TestDrive:\AnotherDestination\FileThatDoesNotExist.txt" | Should Exist
}
}
}

View file

@ -0,0 +1,26 @@
# Tests related to TFS item 1370133 [PSUpgrade] Need -NoNewline parameter on Out-File, Add-Content and Set-Content
# Connect request https://connect.microsoft.com/PowerShell/feedback/details/524739/need-nonewline-parameter-on-out-file-add-content-and-set-content
Describe "Tests for -NoNewline parameter of Out-File, Add-Content and Set-Content" -tags "Feature" {
It "NoNewline parameter works on Out-File" {
$temp = New-TemporaryFile
1..5 | Out-File $temp.FullName -Encoding 'ASCII' -NoNewline
(Get-Content $temp -Encoding Byte).Count | Should Be 5
Remove-Item $temp -ErrorAction SilentlyContinue -Force
}
It "NoNewline parameter works on Set-Content" {
$temp = New-TemporaryFile
Set-Content -Path $temp.FullName -Value 'a','b','c' -Encoding 'ASCII' -NoNewline
(Get-Content $temp -Encoding Byte).Count | Should Be 3
Remove-Item $temp -ErrorAction SilentlyContinue -Force
}
It "NoNewline parameter works on Add-Content" {
$temp = New-TemporaryFile
1..9 | %{Add-Content -Path $temp.FullName -Value $_ -Encoding 'ASCII' -NoNewline}
(Get-Content $temp -Encoding Byte).Count | Should Be 9
Remove-Item $temp -ErrorAction SilentlyContinue -Force
}
}

View file

@ -0,0 +1,221 @@
# This is a Pester test suite to validate the Format-Hex cmdlet in the Microsoft.PowerShell.Utility module.
#
# Copyright (c) Microsoft Corporation, 2015
#
<#
Purpose:
Verify that Format-Hex display the Hexa decmial value for the input data.
Action:
Run Format-Fex.
Expected Result:
Hexa decimal equivalent of the input data is displayed.
#>
Describe "FormatHex" -tags "CI" {
BeforeAll {
Setup -d FormatHexDataDir
$inputText1 = 'Hello World'
$inputText2 = 'This is a bit more text'
$inputFile1 = setup -f "FormatHexDataDir/SourceFile-1.txt" -content $inputText1 -pass
$inputFile2 = setup -f "FormatHexDataDir/SourceFile-2.txt" -content $inputText2 -pass
}
# This test is to validate to pipeline support in Format-Hex cmdlet.
It "ValidatePipelineSupport" {
# InputObject Parameter set should get invoked and
# the input data should be treated as string.
$result = $inputText1 | Format-Hex
$result | Should Not Be $null
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
($actualResult -match $inputText1) | Should Be $true
}
# This test is to validate to pipeline support in Format-Hex cmdlet.
It "ValidateByteArrayInputSupport" {
# InputObject Parameter set should get invoked and
# the input data should be treated as byte[].
$inputBytes = [System.Text.Encoding]::ASCII.GetBytes($inputText1)
$result = Format-Hex -InputObject $inputBytes
$result | Should Not Be $null
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
($actualResult -match $inputText1) | Should Be $true
}
# This test is to validate to input given through Path paramter set in Format-Hex cmdlet.
It "ValidatePathParameterSet" {
$result = Format-Hex -Path $inputFile1
$result | Should Not Be $null
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
($actualResult -match $inputText1) | Should Be $true
}
# This test is to validate to Path paramter set is considered as default in Format-Hex cmdlet.
It "ValidatePathAsDefaultParameterSet" {
$result = Format-Hex $inputFile1
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
($actualResult -match $inputText1) | Should Be $true
}
# This test is to validate to input given through LiteralPath paramter set in Format-Hex cmdlet.
It "ValidateLiteralPathParameterSet" {
$result = Format-Hex -LiteralPath $inputFile1
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
($actualResult -match $inputText1) | Should Be $true
}
# This test is to validate to input given through pipeline. The input being piped from results of Get-hildItem
It "ValidateFileInfoPipelineInput" {
$result = Get-ChildItem $inputFile1 | Format-Hex
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
($actualResult -match $inputText1) | Should Be $true
}
# This test is to validate Encoding formats functionality of Format-Hex cmdlet.
It "ValidateEncodingFormats" {
$result = Format-Hex -InputObject $inputText1 -Encoding ASCII
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
($actualResult -match $inputText1) | Should Be $true
}
# This test is to validate that integers can be piped to the format-hex
It "ValidateIntegerInput" {
$result = 1,2,3,4 | Format-Hex
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
# whitespace sensitive
$actualResult | should be "00000000 01 02 03 04 .... "
}
# This test is to validate that integers can be piped to the format-hex
# and properly represented as characters in the string
It "ValidateIntegerInputThatPresentAsCharacters" {
$result = 65..68 | Format-Hex
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
# whitespace sensitive
$actualResult | should be "00000000 41 42 43 44 ABCD "
}
# This test is to validate that integers can be piped to the format-hex
It "ValidateIntegerRawInput" {
$result = 1,2,3,4 | Format-Hex -Raw
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
# whitespace sensitive
$actualResult | should be "00000000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................"
}
# handle int64
It "ValidateInteger64" {
$result = [int64]::MaxValue | Format-Hex
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString()
# whitespace sensitive
$actualResult | Should Match "00000000 FF FF FF FF FF FF FF 7F ."
}
# handle bytes, int16, int32, and int64
It "Validate combined and reduced number formatting" {
$b = 65 # fits in a byte
$i16 = 32767 # fits in an int16
$i32 = 2147483647 # an int32
$i64 = 9223372036854775807 # an int64
$result = $b,$i16,$i32,$i64 | format-Hex
$result.GetType().Name | should be 'ByteCollection'
$actualResult = $result.ToString()
$actualResult | should Match "00000000 41 FF 7F FF FF FF 7F FF FF FF FF FF FF FF 7F A"
}
# handle bytes, int16, int32, and int64
It "Validate combined and with raw number formatting" {
$b = 65 # fits in a byte
$i16 = 32767 # fits in an int16
$i32 = 2147483647 # an int32
$i64 = 9223372036854775807 # an int64
# this will cause 2 lines to be emitted
$result = $b,$i16,$i32,$i64 | format-Hex -Raw
$result[0].GetType().Name | should be 'ByteCollection'
$result[1].GetType().Name | should be 'ByteCollection'
$result0 = $result[0].ToString()
$result0 | should match "00000000 41 00 00 00 FF 7F 00 00 FF FF FF 7F FF FF FF FF A"
$result1 = $result[1].ToString()
$result1 | should match "00000010 FF FF FF 7F .."
}
# This test is to validate that streamed text does not have buffer underrun problems
It "ValidateEachBufferHasCorrectContentForStreamingText" {
$result = "a" * 30 | Format-Hex
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be 'ByteCollection'
$actualResult = $result.ToString() -split "`r`n"
$actualResult.Count | should be 2
$actualResult[0].ToString() | Should be "00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa"
$actualResult[1].ToString() | Should be "00000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaa "
}
# This test is to validate that files do not have buffer underrun problems
It "ValidateEachBufferHasCorrectContentForFiles" {
$result = Format-Hex -path $InputFile2
$result | Should Not BeNullOrEmpty
$result.Count | should be 2
$result[0].ToString() | Should be "00000000 54 68 69 73 20 69 73 20 61 20 62 69 74 20 6D 6F This is a bit mo"
if ( $IsCoreCLR ) {
$result[1].ToString() | Should be "00000010 72 65 20 74 65 78 74 re text "
}
}
# This test ensures that if we stream bytes from a file, the output is correct
It "ValidateStreamOfBytesFromFileHasProperOutput" {
$result = Get-Content $InputFile1 -Encoding Byte | Format-Hex
$result | Should Not BeNullOrEmpty
$result.GetType().Name | Should Be "ByteCollection"
if ( $IsCoreCLR ) {
$result.ToString() | Should be "00000000 48 65 6C 6C 6F 20 57 6F 72 6C 64 Hello World "
}
}
# This test is to validate the alias for Format-Hex cmdlet.
It "ValidateCmdletAlias" {
try
{
$result = Get-Command fhx -ErrorAction Stop
$result | Should Not BeNullOrEmpty
$result.CommandType.ToString() | Should Be "Alias"
}
catch
{
$_ | Should BeNullOrEmpty
}
}
}

View file

@ -0,0 +1,84 @@
Describe "Using delimiters with Export-CSV and Import-CSV behave correctly" -tags "Feature" {
BeforeAll {
# note, we will not use "," as that's the default for CSV
$delimiters = "/", " ", "@", "#", "$", "\", "&", "(", ")",
"{", "}", "|", "<", ">", ";", "'",
'"', "~", "!", "%", "^", "*", "_", "+", ":",
"?", "-", "=", "[", "]", "."
$defaultDelimiter = [System.Globalization.CultureInfo]::CurrentCulture.TextInfo.ListSeparator
# With CORECLR the CurrentCulture.TextInfo.ListSeparator is not writable, so
# we need to use an entirely new CultureInfo which we can modify
$enCulture = [System.Globalization.CultureInfo]::new("en-us")
$d = get-date
$testCases = @(
foreach($del in $delimiters)
{
@{ Delimiter = $del; Data = $d; ExpectedResult = $d.Ticks }
}
)
function Set-delimiter {
param ( $delimiter )
if ( $IsCoreCLR ) {
$enCulture.TextInfo.ListSeparator = $delimiter
[System.Globalization.CultureInfo]::CurrentCulture = $enCulture
}
else {
[System.Globalization.cultureInfo]::CurrentCulture.TextInfo.ListSeparator = $delimiter
}
}
}
AfterEach {
if ( $IsCoreCLR ) {
$enCulture.TextInfo.ListSeparator = $defaultDelimiter
[System.Globalization.CultureInfo]::CurrentCulture = $enCulture
}
else {
[System.Globalization.CultureInfo]::CurrentCulture.TextInfo.ListSeparator = $defaultDelimiter
}
remove-item -force -ea silentlycontinue TESTDRIVE:/file.csv
}
It "Disallow use of null delimiter" {
$d | export-csv TESTDRIVE:/file.csv
{ import-csv -path TESTDRIVE:/file.csv -delimiter $null } | Should Throw "Delimiter"
}
It "Disallow use of delimiter with useCulture parameter" {
$d | export-csv TESTDRIVE:/file.csv
{ import-csv -path TESTDRIVE:/file.csv -useCulture "," } | Should Throw "','"
}
It "Imports the same properties as exported" {
$a = [pscustomobject]@{ a = 1; b = 2; c = 3 }
$a | export-Csv TESTDRIVE:/file.csv
$b = import-csv TESTDRIVE:/file.csv
@($b.psobject.properties).count | should be 3
$b.a | Should be $a.a
$b.b | Should be $a.b
$b.c | Should be $a.c
}
# parameter generated tests
It 'Delimiter <Delimiter> with CSV import will fail correctly when culture does not match' -testCases $testCases {
param ($delimiter, $Data, $ExpectedResult)
set-Delimiter $delimiter
$Data | export-CSV TESTDRIVE:\File.csv -useCulture
$i = Import-CSV TESTDRIVE:\File.csv
$i.Ticks | Should Not Be $ExpectedResult
}
It 'Delimiter <Delimiter> with CSV import will succeed when culture matches export' -testCases $testCases {
param ($delimiter, $Data, $ExpectedResult)
set-Delimiter $delimiter
$Data | export-CSV TESTDRIVE:\File.csv -useCulture
$i = Import-CSV TESTDRIVE:\File.csv -useCulture
$i.Ticks | Should Be $ExpectedResult
}
It 'Delimiter <Delimiter> with CSV import will succeed when delimiter is used explicitly' -testCases $testCases {
param ($delimiter, $Data, $ExpectedResult)
$Data | export-CSV TESTDRIVE:\File.csv -delimiter $delimiter
$i = Import-CSV TESTDRIVE:\File.csv -delimiter $delimiter
$i.Ticks | Should Be $ExpectedResult
}
}

View file

@ -0,0 +1,54 @@
Describe "GetDateFormatUpdates" -Tags "Feature" {
It "Verifies that FileDate format works" {
$date = Get-Date
$expectedFormat = "{0:yyyyMMdd}" -f $date
$actualFormat = Get-Date -Date $date -Format FileDate
$actualFormat | Should be $expectedFormat
}
It "Verifies that FileDateUniversal format works" {
$date = (Get-Date).ToUniversalTime()
$expectedFormat = "{0:yyyyMMddZ}" -f $date
$actualFormat = Get-Date -Date $date -Format FileDateUniversal
$actualFormat | Should be $expectedFormat
}
It "Verifies that FileDateTime format works" {
$date = Get-Date
$expectedFormat = "{0:yyyyMMddTHHmmssffff}" -f $date
$actualFormat = Get-Date -Date $date -Format FileDateTime
$actualFormat | Should be $expectedFormat
}
It "Verifies that FileDateTimeUniversal format works" {
$date = (Get-Date).ToUniversalTime()
$expectedFormat = "{0:yyyyMMddTHHmmssffffZ}" -f $date
$actualFormat = Get-Date -Date $date -Format FileDateTimeUniversal
$actualFormat | Should be $expectedFormat
}
}
Describe "GetRandomMiscTests" -Tags "Feature" {
It "Shouldn't overflow when using max range" {
$hadError = $false
try
{
## Don't actually need to validate
Get-Random -Minimum ([Int32]::MinValue) -Maximum ([Int32]::MaxValue) -ErrorAction Stop
}
catch
{
$hadError = $true
}
$hadError | Should be $false
}
}

View file

@ -0,0 +1,19 @@
Describe "New-Guid" -Tags "CI" {
It "returns a new guid" {
$guid = New-Guid
$guid.GetType().FullName | Should Be "System.Guid"
}
It "should not be all zeros" {
$guid = New-Guid
$guid.ToString() | Should Not Be "00000000-0000-0000-0000-000000000000"
}
It "should return different guids with each call" {
$guid1 = New-Guid
$guid2 = New-Guid
$guid1.ToString() | Should Not Be $guid2.ToString()
}
}

View file

@ -0,0 +1,38 @@
# This is a Pester test suite to validate the New-TemporaryFile cmdlet in the Microsoft.PowerShell.Utility module.
#
# Copyright (c) Microsoft Corporation, 2015
#
<#
Purpose:
Verify that New-TemporaryFile creates a temporary file.
Action:
Run New-TemporaryFile.
Expected Result:
A FileInfo object for the temporary file is returned.
#>
Describe "NewTemporaryFile" -Tags "CI" {
It "creates a new temporary file" {
$tempFile = New-TemporaryFile
Test-Path $tempFile | Should be $true
$tempFile.GetType().Name | Should be "FileInfo"
if(Test-Path $tempFile)
{
Remove-Item $tempFile -ErrorAction SilentlyContinue -Force
}
}
It "with WhatIf does not create a file" {
New-TemporaryFile -WhatIf | Should Be $null
}
It "has an OutputType of System.IO.FileInfo" {
(Get-Command New-TemporaryFile).OutputType | Should Be "System.IO.FileInfo"
}
}

View file

@ -0,0 +1,86 @@
Describe "Tests for the Import-PowerShellDataFile cmdlet" -Tags "Feature" {
It "Validates error on a missing path" {
$foundError = ""
try
{
Import-PowerShellDataFile -Path /SomeMissingDirectory -ErrorAction Stop
}
catch
{
$foundError = $_.FullyQualifiedErrorId
}
$foundError | Should be "PathNotFound,Microsoft.PowerShell.Commands.ResolvePathCommand"
}
It "Validates error on a directory" {
$foundError = ""
try
{
Import-PowerShellDataFile ${TESTDRIVE} -ErrorAction Stop
}
catch
{
$foundError = $_.FullyQualifiedErrorId
}
$foundError | Should be "CouldNotParseAsPowerShellDataFile,Import-PowerShellDataFile"
}
It "Generates a good error on an insecure file" {
$path = New-TemporaryFile
Set-Content $path '@{ Foo = Get-Process }'
$foundError = ""
try
{
Import-PowerShellDataFile $path -ErrorAction Stop
}
catch
{
$foundError = $_.FullyQualifiedErrorId
}
finally
{
Remove-Item $path
}
$foundError | Should be "InvalidOperationException,Import-PowerShellDataFile"
}
It "Generates a good error on a file that isn't a PowerShell Data File (missing the hashtable root)" {
$path = New-TemporaryFile
Set-Content $path '"Hello World"'
$foundError = ""
try
{
Import-PowerShellDataFile $path -ErrorAction Stop
}
catch
{
$foundError = $_.FullyQualifiedErrorId
}
finally
{
Remove-Item $path
}
$foundError | Should be "CouldNotParseAsPowerShellDataFileNoHashtableRoot,Import-PowerShellDataFile"
}
It "Can parse a PowerShell Data File (detailed tests are in AST.SafeGetValue tests)" {
$path = New-TemporaryFile
Set-Content $path '@{ "Hello" = "World" }'
$result = Import-PowerShellDataFile $path -ErrorAction Stop
$result.Hello | Should be "World"
}
}

View file

@ -0,0 +1,160 @@
Describe "Alias tests" -Tags "CI" {
BeforeAll {
$testPath = Join-Path testdrive:\ ("testAlias\[.test")
New-Item -ItemType Directory -Path $testPath -Force | Out-Null
class TestData
{
[string] $testName
[string] $testFile
[string] $expectedError
TestData($name, $file, $error)
{
$this.testName = $name
$this.testFile = $file
$this.expectedError = $error
}
}
}
Context "Export-Alias literal path" {
BeforeAll {
$csvFile = Join-Path $testPath "alias.csv"
$ps1File = Join-Path $testPath "alias.ps1"
$testCases = @()
$testCases += [TestData]::new("CSV", $csvFile, [NullString]::Value)
$testCases += [TestData]::new("PS1", $ps1File, [NullString]::Value)
$testCases += [TestData]::new("Empty string", "", "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ExportAliasCommand")
$testCases += [TestData]::new("Null", [NullString]::Value, "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ExportAliasCommand")
$testCases += [TestData]::new("Non filesystem provider", 'cert:\alias.ps1', "ReadWriteFileNotFileSystemProvider,Microsoft.PowerShell.Commands.ExportAliasCommand")
}
$testCases | % {
It "for $($_.testName)" {
$test = $_
try
{
Export-Alias -LiteralPath $test.testFile -ErrorAction SilentlyContinue
}
catch
{
$exportAliasError = $_
}
if($test.expectedError -eq $null)
{
Test-Path -LiteralPath $test.testFile | Should Be $true
}
else
{
$exportAliasError.FullyqualifiedErrorId | Should Be $test.expectedError
}
}
AfterEach {
Remove-Item -LiteralPath $test.testFile -Force -ErrorAction SilentlyContinue
}
}
It "when file exists with NoClobber" {
Export-Alias -LiteralPath $csvFile
try
{
Export-Alias -LiteralPath $csvFile -NoClobber
}
catch
{
$exportAliasError = $_
}
$exportAliasError.FullyQualifiedErrorId | Should Be "NoClobber,Microsoft.PowerShell.Commands.ExportAliasCommand"
}
}
Context "Export-All inside a literal path" {
BeforeEach {
Push-Location -LiteralPath $testPath
}
It "with a CSV file" {
Export-Alias "alias.csv"
Test-Path -LiteralPath (Join-Path $testPath "alias.csv") | Should Be $true
}
It "with NoClobber" {
$path = Export-Alias alias.csv
try
{
Export-Alias alias.csv -NoClobber
}
catch
{
$exportAliasError = $_
}
$exportAliasError.FullyQualifiedErrorId | Should Be "NoClobber,Microsoft.PowerShell.Commands.ExportAliasCommand"
}
AfterEach {
Pop-Location
}
}
Context "Import-Alias literal path" {
BeforeAll {
$csvFile = Join-Path $testPath "alias.csv"
$ps1File = Join-Path $testPath "alias.ps1"
$testCases = @()
$testCases += [TestData]::new("Empty string", "", "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ImportAliasCommand")
$testCases += [TestData]::new("Null", [NullString]::Value, "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ImportAliasCommand")
$testCases += [TestData]::new("Non filesystem provider", 'cert:\alias.ps1', "NotSupported,Microsoft.PowerShell.Commands.ImportAliasCommand")
}
$testCases | % {
It "for $($_.testName)" {
$test = $_
try
{
Import-Alias -LiteralPath $test.testFile -ErrorAction SilentlyContinue
}
catch
{
$exportAliasError = $_
}
$exportAliasError.FullyqualifiedErrorId | Should Be $test.expectedError
}
}
It "can be done from a CSV file" {
# alias file definition content
$aliasDefinition = @'
"myuh","update-help","","ReadOnly, AllScope"
'@
$aliasFile = Join-Path $testPath "alias.csv"
$aliasDefinition | Out-File -LiteralPath $aliasFile
Import-Alias -LiteralPath $aliasFile
# Verify that the alias was imported
$definedAlias = Get-Alias myuh
$definedAlias | Should Not Be $null
$definedAlias.Name | Should Be "myuh"
$definedAlias.Definition | Should Be "update-help"
}
}
}

View file

@ -0,0 +1,187 @@
Describe "CliXml test" -Tags "CI" {
BeforeAll {
$testFilePath = Join-Path "testdrive:\" "testCliXml"
$subFilePath = Join-Path $testFilePath ".test"
if(test-path $testFilePath)
{
Remove-Item $testFilePath -Force -Recurse
}
# Create the test File and push the location into specified path
New-Item -Path $testFilePath -ItemType Directory | Out-Null
New-Item -Path $subFilePath -ItemType Directory | Out-Null
Push-Location $testFilePath
class TestData
{
[string] $testName
[object] $inputObject
[string] $expectedError
[string] $testFile
TestData($name, $file, $inputObj, $error)
{
$this.testName = $name
$this.inputObject = $inputObj
$this.expectedError = $error
$this.testFile = $file
}
}
}
AfterAll {
Pop-Location
}
Context "Export-CliXml" {
BeforeAll {
$gpsList = Get-Process powershell
$gps = $gpsList | Select-Object -First 1
$filePath = Join-Path $subFilePath 'gps.xml'
$testData = @()
$testData += [TestData]::new("with path as Null", [NullString]::Value, $gps, "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ExportClixmlCommand")
$testData += [TestData]::new("with path as Empty string", "", $gps, "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ExportClixmlCommand")
$testData += [TestData]::new("with path as non filesystem provider", "cert:\", $gps, "ReadWriteFileNotFileSystemProvider,Microsoft.PowerShell.Commands.ExportClixmlCommand")
}
AfterEach {
Remove-Item $filePath -Force -ErrorAction SilentlyContinue
}
$testData | % {
It "$($_.testName)" {
$test = $_
try
{
Export-Clixml -LiteralPath $test.testFile -InputObject $test.inputObject -Force
}
catch
{
$exportCliXmlError = $_
}
$exportCliXmlError.FullyQualifiedErrorId | Should Be $test.expectedError
}
}
It "can be created with literal path" {
$filePath = Join-Path $subFilePath 'gps.xml'
Export-Clixml -LiteralPath $filePath -InputObject ($gpsList | Select-Object -First 1)
$filePath | Should Exist
$fileContent = Get-Content $filePath
$isExisted = $false
foreach($item in $fileContent)
{
foreach($gpsItem in $gpsList)
{
$checkId = $gpsItem.Id
if (($null -ne $(Select-String -InputObject $item -SimpleMatch $checkId)) -and ($null -ne $(Select-String -InputObject $item -SimpleMatch "Id")))
{
$isExisted = $true
break;
}
}
}
$isExisted | Should Be $true
}
It "can be created with literal path using pipeline" {
$filePath = Join-Path $subFilePath 'gps.xml'
($gpsList | Select-Object -First 1) | Export-Clixml -LiteralPath $filePath
$filePath | Should Exist
$fileContent = Get-Content $filePath
$isExisted = $false
foreach($item in $fileContent)
{
foreach($gpsItem in $gpsList)
{
$checkId = $gpsItem.Id
if (($null -ne $(Select-String -InputObject $item -SimpleMatch $checkId)) -and ($null -ne $(Select-String -InputObject $item -SimpleMatch "Id")))
{
$isExisted = $true
break;
}
}
}
$isExisted | Should Be $true
}
}
Context "Import-CliXML" {
BeforeAll {
$gpsList = Get-Process powershell
$gps = $gpsList | Select-Object -First 1
$filePath = Join-Path $subFilePath 'gps.xml'
$testData = @()
$testData += [TestData]::new("with path as Null", [NullString]::Value, $null, "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ImportClixmlCommand")
$testData += [TestData]::new("with path as Empty string", "", $null, "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ImportClixmlCommand")
$testData += [TestData]::new("with path as non filesystem provider", "cert:\", $null, "ReadWriteFileNotFileSystemProvider,Microsoft.PowerShell.Commands.ImportClixmlCommand")
}
$testData | % {
It "$($_.testName)" {
$test = $_
try
{
Import-Clixml -LiteralPath $test.testFile
}
catch
{
$importCliXmlError = $_
}
$importCliXmlError.FullyQualifiedErrorId | Should Be $test.expectedError
}
}
It "can import from a literal path" {
Export-Clixml -LiteralPath $filePath -InputObject $gps
$filePath | Should Exist
$fileContent = Get-Content $filePath
$fileContent | Should Not Be $null
$importedProcess = Import-Clixml $filePath
$gps.ProcessName | Should Be $importedProcess.ProcessName
$gps.Id | Should Be $importedProcess.Id
}
It "can import from a literal path using pipeline" {
$gps | Export-Clixml -LiteralPath $filePath
$filePath | Should Exist
$fileContent = Get-Content $filePath
$fileContent | Should Not Be $null
$importedProcess = Import-Clixml $filePath
$gps.ProcessName | Should Be $importedProcess.ProcessName
$gps.Id | Should Be $importedProcess.Id
}
It "test follow-up for WinBlue: 161470 - Export-CliXml errors in WhatIf scenarios" {
$testPath = "testdrive:\Bug161470NonExistPath.txt"
Export-Clixml -Path $testPath -InputObject "string" -WhatIf
$testPath | Should Not Exist
}
}
}

View file

@ -0,0 +1,80 @@
Describe "Trace-Command" -tags "Feature" {
Context "Listner options" {
BeforeAll {
$logFile = setup -f traceCommandLog.txt -pass
$actualLogFile = setup -f actualTraceCommandLog.txt -pass
}
AfterEach {
if ( test-path $logfile ) { Remove-Item $logFile }
if ( test-path $actualLogFile ) { Remove-Item $actualLogFile }
}
It "LogicalOperationStack works" -pending:($IsCoreCLR) {
$keyword = "Trace_Command_ListenerOption_LogicalOperationStack_Foo"
$stack = [System.Diagnostics.Trace]::CorrelationManager.LogicalOperationStack
$stack.Push($keyword)
Trace-Command -Name * -Expression {write-output Foo} -ListenerOption LogicalOperationStack -FilePath $logfile
$log = Get-Content $logfile | Where-Object {$_ -like "*LogicalOperationStack=$keyword*"}
$log.Count | Should BeGreaterThan 0
}
It "Callstack works" -pending:($IsCoreCLR) {
Trace-Command -Name * -Expression {write-output Foo} -ListenerOption Callstack -FilePath $logfile
$log = Get-Content $logfile | Where-Object {$_ -like "*Callstack= * System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)*"}
$log.Count | Should BeGreaterThan 0
}
It "Datetime works" {
$expectedDate = Trace-Command -Name * -Expression {Get-Date} -ListenerOption DateTime -FilePath $logfile
$log = Get-Content $logfile | Where-Object {$_ -like "*DateTime=*"}
$results = $log | ForEach-Object {[DateTime]::Parse($_.Split("=")[1])}
## allow a gap of 6 seconds. All traces should be finished within 6 seconds.
$allowedGap = [timespan](60 * 1000 * 1000)
$results | ForEach-Object {
$actualGap = $_ - $expectedDate;
if ($expectedDate -gt $_)
{
$actualGap = $expectedDate - $_;
}
$allowedGap | Should BeGreaterThan $actualGap
}
}
It "None options has no effect" {
Trace-Command -Name * -Expression {write-output Foo} -ListenerOption None -FilePath $actualLogfile
Trace-Command -name * -Expression {write-output Foo} -FilePath $logfile
Compare-Object (Get-Content $actualLogfile) (Get-Content $logfile) | Should BeNullOrEmpty
}
It "ThreadID works" {
Trace-Command -Name * -Expression {write-output Foo} -ListenerOption ThreadId -FilePath $logfile
$log = Get-Content $logfile | Where-Object {$_ -like "*ThreadID=*"}
$results = $log | ForEach-Object {$_.Split("=")[1]}
$results | % { $_ | Should Be ([threading.thread]::CurrentThread.ManagedThreadId) }
}
It "Timestamp creates logs in ascending order" {
Trace-Command -Name * -Expression {write-output Foo} -ListenerOption Timestamp -FilePath $logfile
$log = Get-Content $logfile | Where-Object {$_ -like "*Timestamp=*"}
$results = $log | ForEach-Object {$_.Split("=")[1]}
$sortedResults = $results | Sort-Object
$sortedResults | Should Be $results
}
It "ProcessId logs current process Id" {
Trace-Command -Name * -Expression {write-output Foo} -ListenerOption ProcessId -FilePath $logfile
$log = Get-Content $logfile | Where-Object {$_ -like "*ProcessID=*"}
$results = $log | ForEach-Object {$_.Split("=")[1]}
$results | ForEach-Object { $_ | Should Be $pid }
}
}
}

View file

@ -0,0 +1,64 @@
Describe "FormatData" -tags "Feature" {
Context "Export" {
It "can export all types" {
try
{
$expectAllFormat = Get-FormatData -typename *
$expectAllFormat | Export-FormatData -path $TESTDRIVE\allformat.ps1xml -IncludeScriptBlock
$sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$sessionState.Formats.Clear()
$sessionState.Types.Clear()
$runspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace($sessionState)
$runspace.Open()
$runspace.CreatePipeline("Update-FormatData -AppendPath $TESTDRIVE\allformat.ps1xml").Invoke()
$actualAllFormat = $runspace.CreatePipeline("Get-FormatData -TypeName *").Invoke()
$expectAllFormat.Count | Should Be $actualAllFormat.Count
Compare-Object $expectAllFormat $actualAllFormat | Should Be $null
$runspace.Close()
}
finally
{
Remove-Item -Path $TESTDRIVE\allformat.ps1xml -Force -ErrorAction SilentlyContinue
}
}
It "works with literal path" {
$filename = 'TestDrive:\[formats.ps1xml'
Get-FormatData -TypeName * | Export-FormatData -LiteralPath $filename
(Test-Path -LiteralPath $filename) | Should Be $true
}
It "should overwrite the destination file" {
$filename = 'TestDrive:\ExportFormatDataWithForce.ps1xml'
$unexpected = "SHOULD BE OVERWRITTEN"
$unexpected | Out-File -FilePath $filename -Force
$file = Get-Item $filename
$file.IsReadOnly = $true
Get-FormatData -TypeName * | Export-FormatData -Path $filename -Force
$actual = @(Get-Content $filename)[0]
$actual | Should Not Be $unexpected
}
It "should not overwrite the destination file with NoClobber" {
$filename = "TestDrive:\ExportFormatDataWithNoClobber.ps1xml"
Get-FormatData -TypeName * | Export-FormatData -LiteralPath $filename
try
{
Get-FormatData -TypeName * | Export-FormatData -LiteralPath $filename -NoClobber
}
catch
{
$exportFormatError = $_
}
$exportFormatError.FullyQualifiedErrorId | Should Be 'NoClobber,Microsoft.PowerShell.Commands.ExportFormatDataCommand'
}
}
}

View file

@ -0,0 +1,100 @@
Describe "Object cmdlets" -Tags "CI" {
Context "Group-Object" {
It "AsHashtable returns a hashtable" {
$result = Get-Process | Group-Object -Property ProcessName -AsHashTable
$result["powershell"].Count | Should BeGreaterThan 0
}
It "AsString returns a string" {
$processes = Get-Process | Group-Object -Property ProcessName -AsHashTable -AsString
$result = $processes.Keys | ForEach-Object {$_.GetType()}
$result[0].Name | Should Be "String"
}
}
Context "Tee-Object" {
It "with literal path" {
$path = "TestDrive:\[TeeObjectLiteralPathShouldWorkForSpecialFilename].txt"
Write-Output "Test" | Tee-Object -LiteralPath $path | Tee-Object -Variable TeeObjectLiteralPathShouldWorkForSpecialFilename
$TeeObjectLiteralPathShouldWorkForSpecialFilename | Should Be (Get-Content -LiteralPath $path)
}
}
}
Describe "Object cmdlets" -Tags "CI" {
Context "Measure-Object" {
BeforeAll {
## Powershell language prefers , as an array seperator without "".
## If a number has comma in them it considers it to be the 1000 seperator like "1,000".
## In de-DE language the comma is used as decimal point, but powershell still uses it as a 1000 seperator.
## In case the number has a comma, it is ignored. So, "99,1" becomes 991.
## To work around that behavior, we use ToString() on the expected answer and . for decimal in the input.
$firstValue = "9995788.71"
$expectedFirstValue = $null
$null = [System.Management.Automation.LanguagePrimitives]::TryConvertTo($firstValue, [double], [cultureinfo]::InvariantCulture, [ref] $expectedFirstValue)
$firstObject = new-object psobject
$firstObject | Add-Member -NotePropertyName Header -NotePropertyValue $firstValue
$secondValue = "15847577.7"
$expectedSecondValue = $null
$null = [System.Management.Automation.LanguagePrimitives]::TryConvertTo($secondValue, [double], [cultureinfo]::InvariantCulture, [ref] $expectedSecondValue)
$secondObject = new-object psobject
$secondObject | Add-Member -NotePropertyName Header -NotePropertyValue $secondValue
$testCases = @(
@{ data = @("abc","ABC","Def"); min = "abc"; max = "Def"},
@{ data = @([datetime]::Today, [datetime]::Today.AddDays(-1)); min = ([datetime]::Today.AddDays(-1)).ToString() ; max = [datetime]::Today.ToString() }
@{ data = @(1,2,3,"ABC"); min = 1; max = "ABC"},
@{ data = @(4,2,3,"ABC",1); min = 1; max = "ABC"},
@{ data = @(4,2,3,"ABC",1,"DEF"); min = 1; max = "DEF"},
@{ data = @("111 Test","19"); min = "111 Test"; max = "19"},
@{ data = @("19", "111 Test"); min = "111 Test"; max = "19"},
@{ data = @("111 Test",19); min = "111 Test"; max = 19},
@{ data = @(19, "111 Test"); min = "111 Test"; max = 19},
@{ data = @(100,2,3, "A", 1); min = 1; max = "A"},
@{ data = @(4,2,3, "ABC", 1, "DEF"); min = 1; max = "DEF"},
@{ data = @("abc",[Datetime]::Today,"def"); min = [Datetime]::Today.ToString(); max = "def"}
)
}
It "can compare string representation for minimum" {
$minResult = $firstObject, $secondObject | Measure-Object Header -Minimum
$minResult.Minimum.ToString() | Should Be $expectedFirstValue.ToString()
}
It "can compare string representation for maximum" {
$maxResult = $firstObject, $secondObject | Measure-Object Header -Maximum
$maxResult.Maximum.ToString() | Should Be $expectedSecondValue.ToString()
}
It 'correctly find minimum of (<data>)' -TestCases $testCases {
param($data, $min, $max)
$output = $data | Measure-Object -Minimum
$output.Minimum.ToString() | Should Be $min
}
It 'correctly find maximum of (<data>)' -TestCases $testCases {
param($data, $min, $max)
$output = $data | Measure-Object -Maximum
$output.Maximum.ToString() | Should Be $max
}
It 'returns a GenericMeasureInfoObject' {
$gmi = 1,2,3 | measure-object -max -min
$gmi.GetType().FullName | Should Be 'Microsoft.PowerShell.Commands.GenericMeasureInfo'
}
It 'should return correct error for non-numeric input' {
$gmi = "abc",[Datetime]::Now | measure -sum -max -ev err -ea silentlycontinue
$err | % { $_.FullyQualifiedErrorId | Should Be 'NonNumericInputObject,Microsoft.PowerShell.Commands.MeasureObjectCommand' }
}
It 'should have the correct count' {
$gmi = "abc",[Datetime]::Now | measure -sum -max -ev err -ea silentlycontinue
$gmi.Count | Should Be 2
}
}
}

View file

@ -0,0 +1,63 @@
Describe "String cmdlets" -Tags "CI" {
Context "Select-String" {
BeforeAll {
$sep = [io.path]::DirectorySeparatorChar
$fileName = New-Item 'TestDrive:\selectStr[ingLi]teralPath.txt'
"abc" | Out-File -LiteralPath $fileName.fullname
"bcd" | Out-File -LiteralPath $fileName.fullname -Append
"cde" | Out-File -LiteralPath $fileName.fullname -Append
$fileNameWithDots = $fileName.FullName.Replace("\", "\.\")
$tempFile = New-TemporaryFile
"abc" | Out-File -LiteralPath $tempFile.fullname
"bcd" | Out-File -LiteralPath $tempFile.fullname -Append
"cde" | Out-File -LiteralPath $tempFile.fullname -Append
$driveLetter = $tempFile.PSDrive.Name
$fileNameAsNetworkPath = "\\localhost\$driveLetter`$" + $tempFile.FullName.SubString(2)
Push-Location "$fileName\.."
}
AfterAll {
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
Pop-Location
}
It "LiteralPath with relative path" {
(select-string -LiteralPath (Get-Item -LiteralPath $fileName).Name "b").count | Should Be 2
}
It "LiteralPath with absolute path" {
(select-string -LiteralPath $fileName "b").count | Should Be 2
}
It "LiteralPath with dots in path" {
(select-string -LiteralPath $fileNameWithDots "b").count | Should Be 2
}
It "Network path" -skip:($IsCoreCLR) {
(select-string -LiteralPath $fileNameAsNetworkPath "b").count | Should Be 2
}
It "throws error for non filesystem providers" {
$aaa = "aaaaaaaaaa"
select-string -literalPath variable:\aaa "a" -ErrorAction SilentlyContinue -ErrorVariable selectStringError
$selectStringError.FullyQualifiedErrorId | Should Be 'ProcessingFile,Microsoft.PowerShell.Commands.SelectStringCommand'
}
It "throws parameter binding exception for invalid context" {
{ select-string It $PSScriptRoot -Context -1,-1 } | Should Throw Context
}
It "match object supports RelativePath method" {
$file = "Modules${sep}Microsoft.PowerShell.Utility${sep}Microsoft.PowerShell.Utility.psd1"
$match = Select-String CmdletsToExport $pshome/$file
$match.RelativePath($pshome) | Should Be $file
$match.RelativePath($pshome.ToLower()) | Should Be $file
$match.RelativePath($pshome.ToUpper()) | Should Be $file
}
}
}

View file

@ -0,0 +1,129 @@
Describe "TestData cmdlets" -Tags "CI" {
Context "Get-TypeData" {
It "System.Array" {
(Get-TypeData System.Array).TypeName | Should Be System.Array
# Supports pipelining?
("System.Array" | Get-TypeData).TypeName | Should Be System.Array
}
It "Type accelerators" {
(Get-TypeData Array).TypeName | Should Be System.Array
(Get-TypeData psCredential).TypeName | Should Be System.Management.Automation.PSCredential
}
It "Accept multiple types" {
$types = Get-TypeData System.Array, System.Management.Automation* | Sort-Object -Property TypeName
$types[0].TypeName | Should Be System.Array
for($i = 1; $i -lt $types.Count; $i++)
{
$types[$i].TypeName.StartsWith("System.Management.Automation") | Should Be $true
}
}
It "System.Object" {
Get-TypeData System.Object | Should Be $null
}
}
# The rest of these tests do their work in another runspace to avoid messing up the current runspace
Context "Update-TypeData" {
BeforeAll {
$script:ps = [PowerShell]::Create()
}
BeforeEach {
$ps.Commands.Clear()
$ps.Streams.Error.Clear()
}
AfterAll {
$ps.Dispose()
$script:ps = $null
}
It "TypeAdapter parameter" {
$type = $ps.AddScript(@"
Update-TypeData -TypeName Void -TypeAdapter Microsoft.PowerShell.Cim.CimInstanceAdapter
Get-TypeData System.Void
"@).Invoke()
$type[0].TypeName | Should Be System.Void
$type[0].TypeAdapter.FullName | Should Be Microsoft.PowerShell.Cim.CimInstanceAdapter
}
}
Context "Remove-TypeData" {
BeforeAll {
$script:ps = [PowerShell]::Create()
Setup -F dummy1.types.ps1xml -Content "<Types><Type><Name>yyyDummy</Name><Members><ScriptProperty><Name>yyyDummy</Name><GetScriptBlock>'yyyDummy'</GetScriptBlock></ScriptProperty></Members></Type></Types>"
Setup -F dummy2.types.ps1xml -Content "<Types><Type><Name>zzzDummy</Name><Members><ScriptProperty><Name>zzzDummy</Name><GetScriptBlock>'zzzDummy'</GetScriptBlock></ScriptProperty></Members></Type></Types>"
}
BeforeEach {
$ps.Commands.Clear()
$ps.Streams.Error.Clear()
}
AfterAll {
$ps.Dispose()
$script:ps = $null
}
It "Remove type that doesn't exist" {
$typeName = "TypeThatDoesNotExistsAnywhere" + (Get-Random)
$ps.AddScript("Remove-TypeData -TypeName $typeName").Invoke()
$ps.Streams.Error[0].FullyQualifiedErrorId | Should Be "TypesDynamicRemoveException,Microsoft.PowerShell.Commands.RemoveTypeDataCommand"
}
##{ All of the following It blocks are intended to run in sequence, so don't reorder them.
It "Add type file," {
$ps.AddScript("Update-TypeData -AppendPath $TestDrive\dummy1.types.ps1xml").Invoke()
$ps.Streams.Error.Count | Should Be 0
}
It "Get type data from file just added," {
$type = $ps.AddScript("Get-TypeData -TypeName yyyDummy").Invoke()
$ps.Streams.Error.Count | Should Be 0
$type[0].TypeName | Should Be yyyDummy
}
It "Remove type file just added," {
$ps.AddScript("Remove-TypeData -Path $TestDrive\dummy1.types.ps1xml").Invoke()
$ps.Streams.Error.Count | Should Be 0
}
It "Make sure type was removed" {
$type = $ps.AddScript("Get-TypeData -TypeName yyyDummy").Invoke()
$type.Count | Should Be 0
}
It "Add another type file," {
$ps.AddScript("Update-TypeData -AppendPath $TestDrive\dummy2.types.ps1xml").Invoke()
$ps.Streams.Error.Count | Should Be 0
}
It "Now add some type data to one of those newly added types" {
$ps.AddScript("Update-TypeData -TypeName zzzDummy -MemberType NoteProperty -MemberName DynamicDummyProperty -Value 10").Invoke()
$ps.Streams.Error.Count | Should Be 0
}
It "Remove the newly type file," {
$ps.AddScript("Remove-TypeData -Path $TestDrive\dummy2.types.ps1xml").Invoke()
$ps.Streams.Error.Count | Should Be 0
}
It "Remove the newly type file a second time, should error," {
$ps.AddScript("Remove-TypeData -Path $TestDrive\dummy2.types.ps1xml").Invoke()
$ps.Streams.Error.Count | Should Be 1
$ps.Streams.Error[0].FullyQualifiedErrorId | Should Be "TypeFileNotExistsInCurrentSession,Microsoft.PowerShell.Commands.RemoveTypeDataCommand"
}
It "Dynamic property added should still be there" {
$res = $ps.AddScript("Get-TypeData -TypeName zzzDummy").Invoke()
$res.Count | Should Be 1
$res[0].Members.Keys[0] | Should Be DynamicDummyProperty
}
##} All of the preceding It blocks are intended to run in sequence, so don't reorder them.
}
}

View file

@ -0,0 +1,68 @@
Describe "XML cmdlets" -Tags "Feature" {
Context "Select-XML" {
BeforeAll {
$fileName = New-Item -Path 'TestDrive:\testSelectXml.xml'
Push-Location "$fileName\.."
"<Root>" | out-file -LiteralPath $fileName
" <Node Attribute='blah' />" | out-file -LiteralPath $fileName -Append
"</Root>" | out-file -LiteralPath $fileName -Append
$fileNameWithDots = $fileName.FullName.Replace("\", "\.\")
$driveLetter = [string]($fileName.FullName)[0]
$fileNameAsNetworkPath = "\\localhost\$driveLetter`$" + $fileName.FullName.SubString(2)
class TestData
{
[string] $testName
[hashtable] $parameters
TestData($name, $parameters)
{
$this.testName = $name
$this.parameters = $parameters
}
}
$testcases = @()
$testcases += [TestData]::new('literalpath with relative paths', @{LiteralPath = $fileName.Name; XPath = 'Root'})
$testcases += [TestData]::new('literalpath with absolute paths', @{LiteralPath = $fileName.FullName; XPath = 'Root'})
$testcases += [TestData]::new('literalpath with path with dots', @{LiteralPath = $fileNameWithDots; XPath = 'Root'})
if ( ! $IsCoreCLR ) {
$testcases += [TestData]::new('literalpath with network path', @{LiteralPath = $fileNameAsNetworkPath; XPath = 'Root'})
}
$testcases += [TestData]::new('path with relative paths', @{Path = $fileName.Name; XPath = 'Root'})
$testcases += [TestData]::new('path with absolute paths', @{Path = $fileName.FullName; XPath = 'Root'})
$testcases += [TestData]::new('path with path with dots', @{Path = $fileNameWithDots; XPath = 'Root'})
if ( ! $IsCoreCLR ) {
$testcases += [TestData]::new('path with network path', @{Path = $fileNameAsNetworkPath; XPath = 'Root'})
}
}
AfterAll {
Remove-Item -LiteralPath $fileName -Force -ErrorAction SilentlyContinue
Pop-Location
}
$testcases | % {
$params = $_.parameters
It $_.testName {
@(Select-XML @params).Count | Should Be 1
}
}
It "literalpath with non filesystem path" {
$__data = "abcdefg"
Select-XML -literalPath variable:__data "Root" -ErrorVariable selectXmlError -ErrorAction SilentlyContinue
$selectXmlError.FullyQualifiedErrorId | Should Be 'ProcessingFile,Microsoft.PowerShell.Commands.SelectXmlCommand'
}
It "path with non filesystem path" {
$__data = "abcdefg"
Select-XML -Path variable:\__data "Root" -ErrorVariable selectXmlError -ErrorAction SilentlyContinue
$selectXmlError.FullyQualifiedErrorId | Should Be 'ProcessingFile,Microsoft.PowerShell.Commands.SelectXmlCommand'
}
}
}

View file

@ -0,0 +1,23 @@
{
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/FormatHex.Tests.ps1": "Microsoft.PowerShell.Utility/FormatHex.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/ImportExportCSV.Delimiter.Tests.ps1": "Microsoft.PowerShell.Utility/ImportExportCSV.Delimiter.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/MiscCmdletUpdates.Tests.ps1": "Microsoft.PowerShell.Utility/MiscCmdletUpdates.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/NewGuid.Tests.ps1": "Microsoft.PowerShell.Utility/NewGuid.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/NewTemporaryFile.Tests.ps1": "Microsoft.PowerShell.Utility/NewTemporaryFile.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/Pester.Commands.Cmdlets.ArchiveTests.ps1": "Microsoft.PowerShell.Archive/Pester.Commands.Cmdlets.Archive.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/SamplePreCreatedArchive.archive": "Microsoft.PowerShell.Archive/SamplePreCreatedArchive.archive",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/Pester.Commands.Cmdlets.GetCommand.ps1": "Microsoft.PowerShell.Core/Pester.Commands.Cmdlets.GetCommand.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/Pester.Commands.Cmdlets.JsonTests.ps1": "Microsoft.PowerShell.Utility/Pester.Commands.Cmdlets.Json.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/Pester.Commands.Cmdlets.NoNewlineParameter.Tests.ps1": "Microsoft.PowerShell.Management/Pester.Commands.Cmdlets.NoNewlineParameter.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/Pester.History.Tests.ps1": "Microsoft.PowerShell.Core/History.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/Pester.Management.Copy.Item.Tests.ps1": "Microsoft.PowerShell.Management/Copy.Item.Tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.alias.tests.ps1": "Microsoft.PowerShell.Utility/alias.tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.clixml.tests.ps1": "Microsoft.PowerShell.Utility/clixml.tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.command.tests.ps1": "Microsoft.PowerShell.Utility/command.tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.formatdata.tests.ps1": "Microsoft.PowerShell.Utility/formatdata.tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.object.tests.ps1": "Microsoft.PowerShell.Utility/object.tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/Pester.Utility.PowerShellData.tests.ps1": "Microsoft.PowerShell.Utility/PowerShellData.tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.string.tests.ps1": "Microsoft.PowerShell.Utility/string.tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.typedata.tests.ps1": "Microsoft.PowerShell.Utility/typedata.tests.ps1",
"monad/tests/ci/PowerShell/tests/Commands/Cmdlets/pester.utility.xml.tests.ps1": "Microsoft.PowerShell.Utility/xml.tests.ps1",
}