Skip to content

Commit

Permalink
Enable only discovery (#1870)
Browse files Browse the repository at this point in the history
Add option to skip run and return the result object right after discovery.
  • Loading branch information
nohwnd committed Mar 21, 2021
1 parent 3df14ff commit 890a21c
Show file tree
Hide file tree
Showing 24 changed files with 1,718 additions and 1,299 deletions.
17 changes: 14 additions & 3 deletions src/Pester.RSpec.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,18 @@ function Add-RSpecTestObjectProperties {
# adds properties that are specific to RSpec to the result object
# this includes figuring out the result
# formatting the failure message and stacktrace
$discoveryOnly = $PesterPreference.Run.SkipRun.Value

$TestObject.Result = if ($TestObject.Skipped) {
"Skipped"
}
elseif ($TestObject.Passed) {
"Passed"
}
elseif ($TestObject.ShouldRun -and (-not $TestObject.Executed -or -not $TestObject.Passed)) {
elseif (-not $discoveryOnly -and $TestObject.ShouldRun -and (-not $TestObject.Executed -or -not $TestObject.Passed)) {
"Failed"
}
elseif ($discoveryOnly -and 0 -lt $TestObject.ErrorRecord.Count) {
"Failed"
}
else {
Expand All @@ -134,6 +138,7 @@ function Add-RSpecBlockObjectProperties ($BlockObject) {
}

function PostProcess-RspecTestRun ($TestRun) {
$discoveryOnly = $PesterPreference.Run.SkipRun.Value

Fold-Run $Run -OnTest {
param($t)
Expand Down Expand Up @@ -173,7 +178,10 @@ function PostProcess-RspecTestRun ($TestRun) {
elseif ($b.Passed) {
"Passed"
}
elseif ($b.ShouldRun -and (-not $b.Executed -or -not $b.Passed)) {
elseif (-not $discoveryOnly -and $b.ShouldRun -and (-not $b.Executed -or -not $b.Passed)) {
"Failed"
}
elseif ($discoveryOnly -and 0 -lt $b.ErrorRecord.Count) {
"Failed"
}
else {
Expand All @@ -200,7 +208,10 @@ function PostProcess-RspecTestRun ($TestRun) {
elseif ($b.Passed) {
"Passed"
}
elseif ($b.ShouldRun -and (-not $b.Executed -or -not $b.Passed)) {
elseif (-not $discoveryOnly -and $b.ShouldRun -and (-not $b.Executed -or -not $b.Passed)) {
"Failed"
}
elseif ($discoveryOnly -and 0 -lt $b.ErrorRecord.Count) {
"Failed"
}
else {
Expand Down
38 changes: 10 additions & 28 deletions src/Pester.Runtime.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -141,34 +141,7 @@ function ConvertTo-DiscoveredBlockContainer {
$Block
)

# takes a root block and converts it to a discovered block container
# that we can publish from Find-Test, because keeping everything a block makes the internal
# code simpler
$container = $Block.BlockContainer
$content = tryGetProperty $container Content
$type = tryGetProperty $container Type

# TODO: Add other properties that are relevant to found tests
$b = $Block | &$SafeCommands['Select-Object'] -ExcludeProperty @(
"Parent"
"Name"
"Tag"
"First"
"Last"
"StandardOutput"
"Passed"
"Skipped"
"Executed"
"Path",
"StartedAt",
"Duration",
"Aggregated*"
) -Property @(
@{n = "Content"; e = { $content } }
@{n = "Type"; e = { $type } },
'*'
)

$b = [Pester.Container]::CreateFromBlock($Block)
$b
}

Expand Down Expand Up @@ -1902,6 +1875,15 @@ function Invoke-Test {

$found = Discover-Test -BlockContainer $BlockContainer -Filter $Filter -SessionState $SessionState

if ($PesterPreference.Run.SkipRun.Value) {
foreach ($f in $found) {
ConvertTo-DiscoveredBlockContainer -Block $f
}

& $SafeCommands["Write-Host"] -ForegroundColor Magenta "`nTest run was skipped."

return
}
# $errs = $SessionState.PSVariable.Get("Error").Value
# $errsCount = $errs.Count
# if ($errsCount -lt $originalErrorCount) {
Expand Down
42 changes: 42 additions & 0 deletions src/csharp/Pester/BoolOption.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// those types implement Pester configuration in a way that allows it to show information about each item
// in the powershell console without making it difficult to use. there are two tricks being used:
// - constructor taking IDictionary (most likely a hashtable) that will populate the object,
// this allows the object to be constructed from a hashtable simply by casting to the type
// both implicitly and explicitly, so the user does not have to care about what types are used
// but will still get the benefit of the data annotation in the object. Usage is like this:
// `$config.Debug = @{ WriteDebugMessages = $true; WriteDebugMessagesFrom = "Mock*" }`, which
// will populate the config with the given values while keeping all other values to the default.
// - to be able to assign values like this: `$config.Should.ErrorAction = 'Continue'` but still
// get the documentation when accessing the property, we use implicit casting to get an instance of
// StringOption, and then populate it from the option object that is already assigned to the property
//
// lastly most of the types go to Pester namespace to keep them from the global namespace because they are
// simple to use by implicit casting, with the only exception of PesterConfiguration because that is helpful
// to have in "type accelerator" form, but without the hassle of actually adding it as a type accelerator
// that way you can easily do `[PesterConfiguration]::Default` and then inspect it, or cast a hashtable to it

namespace Pester
{
public class BoolOption : Option<bool>
{
public BoolOption(BoolOption option, bool value) : base(option, value)
{

}

public BoolOption(string description, bool defaultValue) : base(description, defaultValue, defaultValue)
{

}

public BoolOption(string description, bool defaultValue, bool value) : base(description, defaultValue, value)
{

}

public static implicit operator BoolOption(bool value)
{
return new BoolOption(string.Empty, value, value);
}
}
}
38 changes: 38 additions & 0 deletions src/csharp/Pester/Cloner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Linq;

// those types implement Pester configuration in a way that allows it to show information about each item
// in the powershell console without making it difficult to use. there are two tricks being used:
// - constructor taking IDictionary (most likely a hashtable) that will populate the object,
// this allows the object to be constructed from a hashtable simply by casting to the type
// both implicitly and explicitly, so the user does not have to care about what types are used
// but will still get the benefit of the data annotation in the object. Usage is like this:
// `$config.Debug = @{ WriteDebugMessages = $true; WriteDebugMessagesFrom = "Mock*" }`, which
// will populate the config with the given values while keeping all other values to the default.
// - to be able to assign values like this: `$config.Should.ErrorAction = 'Continue'` but still
// get the documentation when accessing the property, we use implicit casting to get an instance of
// StringOption, and then populate it from the option object that is already assigned to the property
//
// lastly most of the types go to Pester namespace to keep them from the global namespace because they are
// simple to use by implicit casting, with the only exception of PesterConfiguration because that is helpful
// to have in "type accelerator" form, but without the hassle of actually adding it as a type accelerator
// that way you can easily do `[PesterConfiguration]::Default` and then inspect it, or cast a hashtable to it

namespace Pester
{
internal static class Cloner
{
public static T ShallowClone<T>(T obj) where T : new()
{
var cfg = new T();
var properties = typeof(T).GetProperties().ToList();

foreach (var p in properties.Where(p => p.CanRead && p.CanWrite))
{
var value = p.GetValue(obj);
p.SetValue(cfg, value);
}

return cfg;
}
}
}

0 comments on commit 890a21c

Please sign in to comment.