Git Product home page Git Product logo

indented.stubcommand's People

Contributors

indented-automation avatar johlju avatar waffle-iron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

indented.stubcommand's Issues

Generated functions: Help content

FEATURE: Generated functions should contain a copy of help content
  Help content should include:
      Synopsis
      Parameter specific help
  Inclusion of help content in a stub should be optional (at command level)

Needs to preserve Parameter Position information

Example:
Get-Recipient user
Has WarningAction as the first positional parameter instead of the correct identity

Cannot bind parameter 'WarningAction'. Cannot convert value "user" to type "System.Management.Automation.ActionPreference". Error: "Unable to match the identifier name satinder to a valid enumerator name. Specify one of the following enumerator names and try again:
SilentlyContinue, Stop, Continue, Inquire, Ignore, Suspend"
At C:\Users\jgrote\AppData\Local\Temp\tmp_llmiwitj.mxx\tmp_llmiwitj.mxx.psm1:29118 char:29
+                             @clientSideParameters `
+                             ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Invoke-Command], ParentContainsErrorRecordException        
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeCommandCommand

While get-recipient -identity user works fine.

Generated types: Nested / sub classes

FEATURE: Nested or sub classes should be supported
    The stub type should be able to determine if a class is a sub-class
    The outer and inner types should be fabricated

Incomplete recreation is demonstrated by:

Add-Type -TypeDefinition '
    public class outerClass
    {
        public class innerClass {
            public string Inner = "inner";

            public innerClass() { }
        }

        public string Outer = "outer";

        public outerClass() { }
    }
'
New-StubType ([outerClass+innerClass])

Bug: Enum handler

Verify the enum handler correctly parses enums where a value has two names.

Nice to have: Make enums look pretty.

Generated types: Type conversion

FEATURE: Simulate PS type conversion for type stubs
   Constructors should more accurately reflect the constructors on the source object
   Static create methods should be re-implemented.
   Static parse methods should be re-implemented.

As the internal logic behind a methods and constructors cannot be reasonably implemented supporting these is more of an effort to ensure parameter type binding is reasonably accurately simulated.

IComparable issue with Test-Connection

Something in how it surfaces parameters I assume.
new-stubcommand -commandname test-connection -functionbody {'this works!'}

New-StubCommand : Cannot compare "System.Management.Automation.ParameterMetadata" because it is not IComparable.
At C:\Users\jgrote\Documents\WindowsPowerShell\Modules\Indented.StubCommand\1.4.0\Indented.StubCommand.psm1:347 char:40

  • ... Get-Command $CommandName | New-StubCommand @PSBoundParameters
  •                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (:) [Write-Error], RuntimeException
    • FullyQualifiedErrorId : NotIcomparable,New-StubCommand

Generated commands: OutputType

The OutputType attribute trusts the name property to hold a .NET type name. This assumption is flawed as the OutputType attribute may use a string.

This problem is exhibits when creating a stub of a module based on a WMI class (cdxml module) such as the Storage module.

OutputType must fill .NET types from the Type property. If Type is empty, use Name as a string.

Problem with missing type after running New-StubModule

I ran the following command

New-StubModule -FromModule ActiveDirectory -Path C:\projects\stub -FunctionBody {
    throw '{0}: StubNotImplemented' -f $MyInvocation.MyCommand
}

When using the stubs in the unit tests, the type Microsoft.ActiveDirectory.Management.Commands.ValidateNotNullOrEmptyADEntityAttribute was missing (not sure why). So I generated that with

New-StubType -Type Microsoft.ActiveDirectory.Management.Commands.ValidateNotNullOrEmptyADEntityAttribute

Which gave me the following result, which I just copied into the correct namespace in the stub module (the namespace already existed and contained enums).

Add-Type -IgnoreWarnings -TypeDefinition @'
namespace Microsoft.ActiveDirectory.Management.Commands
{
    public class ValidateNotNullOrEmptyADEntityAttribute
    {
        // Constructor
        public ValidateNotNullOrEmptyADEntityAttribute() { }

        // Property
        public System.Object TypeId { get; set; }

    }

}

'@

When running the tests again I get the following error when Pester tries to use the mock, when Pester is building the dynamic parameters.

MethodException: Cannot find an overload for "Add" and the argument count: "1".
        CmdletInvocationException: Cannot find an overload for "Add" and the argument count: "1".
        ParameterBindingException: Cannot retrieve the dynamic parameters for the cmdlet. Cannot find an overload for "Add" and the argument count: "1".

The same error can be reproduced by the following code.

Add-Type -IgnoreWarnings -TypeDefinition @'
namespace Microsoft.ActiveDirectory.Management.Commands
{
    public class ValidateNotNullOrEmptyADEntityAttribute
    {
        // Constructor
        public ValidateNotNullOrEmptyADEntityAttribute() { }

        // Property
        public System.Object TypeId { get; set; }
    }
}
'@

$attributes = New-Object System.Collections.Generic.List[Attribute]
$attribute = New-Object Microsoft.ActiveDirectory.Management.Commands.ValidateNotNullOrEmptyADEntityAttribute
$attributes.Add($attribute)

What is missing from the stub type output for it to work to be added into an array?

Generated modules: Manifest

Scenario: I use Requires to dictate a specific version of a required module
    Each stub module must include a manifest describing the source module version

Generated types: Property / Field members

FEATURE: I want to create an instance of a stub object
   The instance should include a reasonable copy of the public properties and fields from the source object
   Fabricated properties do not need to be backed by a field

Including property members may increase the number of required types. Whether or not there is benefit in this needs to be explored.

Initially I property types derived from a foreign assembly (which is not already stubbed) will be replaced with "object".

DefaultParameterSetName

My use case is writing proxy commands, but I think this applies to other use cases.

Consider the invocation "Get-WmiObject -Class Win32_ComputerSystem"

Microsoft.PowerShell.Management\Get-WmiObject returns with this call. The generated stub command for Get-WmiObject throws "Parameter set cannot be resolved using the specified named parameters."

I think this is because of DefaultParameterSetName not being implemented.

Resulting StubTypes return may return warnings

The example created type

if (-not ("Microsoft.Dism.Commands.LogLevel" -as [Type])) {
    Add-Type '
    namespace Microsoft.Dism.Commands
    {
        public enum LogLevel : int
        {
            Errors = 0,
            Warnings = 1,
            WarningsInfo = 2
        }
    }
    ' 
}

may return warnings saying "the generated type does not define public methods or properties" (translated to english). This may disturb pester results.

 if (-not ("Microsoft.Dism.Commands.LogLevel" -as [Type])) {
    Add-Type '
    namespace Microsoft.Dism.Commands
    {
        public enum LogLevel : int
        {
            Errors = 0,
            Warnings = 1,
            WarningsInfo = 2
        }
    }
    ' -IgnoreWarnings
}

Does not return this warning.

Problem using Assert-MockCalled when dynamic parameter is using type from module

The stub cmdlet Move-ADDirectoryServer passes a string in the parameter Site. But the parameter Site is of the type Microsoft.ActiveDirectory.Management.ADReplicationSite which is a stub type.
When using an assert like below, the ToString() method does not return anything, neither does $Site.Name which is a property of the type Microsoft.ActiveDirectory.Management.ADReplicationSite.

Example of assert that fails.

Assert-MockCalled -CommandName Move-ADDirectoryServer -Times 1 -ParameterFilter {
    $Site.ToString() -eq $correctSiteName
}

The stub cmdlet looks like this.

function Move-ADDirectoryServer {
    <#
    .SYNOPSIS
        Move-ADDirectoryServer [-Identity] <ADDirectoryServer> [-Site] <ADReplicationSite> [-WhatIf] [-Confirm] [-AuthType <ADAuthType>] [-Credential <pscredential>] [-Server <string>] [<CommonParameters>]
    #>

    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='Medium', HelpUri='http://go.microsoft.com/fwlink/?LinkId=219321')]
    param ( )

    dynamicparam {
        $parameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

        # AuthType
        $attributes = New-Object System.Collections.Generic.List[Attribute]

        $attribute = New-Object System.Management.Automation.ParameterAttribute
        $attributes.Add($attribute)

        $parameter = New-Object System.Management.Automation.RuntimeDefinedParameter("AuthType", [Microsoft.ActiveDirectory.Management.ADAuthType], $attributes)
        $parameters.Add("AuthType", $parameter)

        # Credential
        $attributes = New-Object System.Collections.Generic.List[Attribute]

        $attribute = New-Object System.Management.Automation.ParameterAttribute
        $attributes.Add($attribute)

        $attribute = New-Object System.Management.Automation.ValidateNotNullOrEmptyAttribute
        $attributes.Add($attribute)

        $attribute = New-Object System.Management.Automation.CredentialAttribute
        $attributes.Add($attribute)

        $parameter = New-Object System.Management.Automation.RuntimeDefinedParameter("Credential", [System.Management.Automation.PSCredential], $attributes)
        $parameters.Add("Credential", $parameter)

        # Identity
        $attributes = New-Object System.Collections.Generic.List[Attribute]

        $attribute = New-Object System.Management.Automation.ValidateNotNullAttribute
        $attributes.Add($attribute)

        $attribute = New-Object System.Management.Automation.ParameterAttribute
        $attribute.Position = 0
        $attribute.Mandatory = $True
        $attribute.ValueFromPipeline = $True
        $attributes.Add($attribute)

        $parameter = New-Object System.Management.Automation.RuntimeDefinedParameter("Identity", [Microsoft.ActiveDirectory.Management.ADDirectoryServer], $attributes)
        $parameters.Add("Identity", $parameter)

        # Server
        $attributes = New-Object System.Collections.Generic.List[Attribute]

        $attribute = New-Object System.Management.Automation.ValidateNotNullOrEmptyAttribute
        $attributes.Add($attribute)

        $attribute = New-Object System.Management.Automation.ParameterAttribute
        $attributes.Add($attribute)

        $parameter = New-Object System.Management.Automation.RuntimeDefinedParameter("Server", [System.String], $attributes)
        $parameters.Add("Server", $parameter)

        # Site
        $attributes = New-Object System.Collections.Generic.List[Attribute]

        $attribute = New-Object System.Management.Automation.ParameterAttribute
        $attribute.Position = 1
        $attribute.Mandatory = $True
        $attributes.Add($attribute)

        $attribute = New-Object System.Management.Automation.ValidateNotNullAttribute
        $attributes.Add($attribute)

        $parameter = New-Object System.Management.Automation.RuntimeDefinedParameter("Site", [Microsoft.ActiveDirectory.Management.ADReplicationSite], $attributes)
        $parameters.Add("Site", $parameter)

        return $parameters
    }

    end {
        throw '{0}: StubNotImplemented' -f $MyInvocation.MyCommand
    }
}

The stub type ADReplicationSite looks like this.

    public class ADReplicationSite
    {
        // Constructor
        public ADReplicationSite() { }
        public ADReplicationSite(System.String identity) { }
        public ADReplicationSite(System.Guid guid) { }
        public ADReplicationSite(Microsoft.ActiveDirectory.Management.ADObject identity) { }
        public ADReplicationSite(Microsoft.ActiveDirectory.Management.ADDirectoryServer directoryServer) { }

        // Property
        public System.String DistinguishedName { get; set; }
        public System.String Name { get; set; }
        public System.String ObjectClass { get; set; }
        public System.Nullable<System.Guid> ObjectGuid { get; set; }
        public System.Collections.ICollection PropertyNames { get; set; }
        public System.Collections.Generic.ICollection<System.String> AddedProperties { get; set; }
        public System.Collections.Generic.ICollection<System.String> RemovedProperties { get; set; }
        public System.Collections.Generic.ICollection<System.String> ModifiedProperties { get; set; }
        public System.Int32 PropertyCount { get; set; }
        public Microsoft.ActiveDirectory.Management.ADPropertyValueCollection Item { get; set; }
    }

So the above assert failed because ToString() does not exist in the stub type, and $Site.Name does not contain the string value passed to the parameter Site, of the cmdlet Move-ADDirectoryServer, because there are no logic in the stub class ADReplicationSite` to handle that.

If I add logic to the class ADReplicationSite constructor that takes a string as argument, and change the test code to assert on $Site.Name then the assert works. I could have added the ToString() method to return the Site.Name property, but that is more uncertain if that is what the real ToString() method does.

Changed logic in the class ADReplicationSite. Just showing the relevant parts.

    public class ADReplicationSite
    {
        // Constructor
        ...
        public ADReplicationSite(System.String identity) { this.Name = identity; }
        ...

        // Property
        ...
        public System.String Name { get; set; }
        ...
    }

Changed logic in the assert in the test.

Assert-MockCalled -CommandName Move-ADDirectoryServer -Times 1 -ParameterFilter {
    $Site.Name -eq $correctSiteName
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.