Skip to content

Commit

Permalink
Bug Fix, Document Addition
Browse files Browse the repository at this point in the history
* NuGet: Fixed #23: Can't be replaced the method that exposes the type of GAC unregistered assembly. => Make the resolve process to find more heuristically the referenced assemblies of the assembly that is specified by -AssemblyFrom.
* NuGet: Fixed #24: Add Comment-Based Help. => It has been completed generally.
  • Loading branch information
urasandesu committed Oct 16, 2014
1 parent dcffcbe commit a9c39cd
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 4 deletions.
10 changes: 8 additions & 2 deletions Nuspec/Prig.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>Prig</id>
<version>0.0.0-alpha9</version>
<version>0.0.0-alpha10</version>
<title>Prig: Open Source Alternative to Microsoft Fakes</title>
<authors>Akira Sugiura</authors>
<owners>Akira Sugiura</owners>
Expand All @@ -17,7 +17,13 @@
</description>
<copyright>(c) 2014 Akira Sugiura. All rights reserved.</copyright>
<tags>tdd isolation mock mocks mocking fake fakes faking unittest unittesting</tags>
<releaseNotes>Version 0.0.0-alpha9
<releaseNotes>Version 0.0.0-alpha10
* Pre-release 10.
* Fixed #23: Can't be replaced the method that exposes the type of GAC unregistered assembly.
* Fixed #24: Add Comment-Based Help.


Version 0.0.0-alpha9
* Pre-release 9.
* Fixed #16: Nested Type can't be resolved in its indirection stub.
* Fixed #17: Prig can't uninstall correctly against the solution that contains multiple test projects.
Expand Down
31 changes: 29 additions & 2 deletions Nuspec/tools/Invoke-PilotStubber.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ param (
$WhatIf
)

trap {
Write-Error ($Error[0] | Out-String)
exit -1
}

Write-Verbose ('ReferenceFrom : {0}(Type: {1})' -f $ReferenceFrom, ($ReferenceFrom.GetType()))
Write-Verbose ('Assembly : {0}' -f $Assembly)
Write-Verbose ('Target Framework Version : {0}' -f $TargetFrameworkVersion)
Expand All @@ -75,7 +80,8 @@ if (![string]::IsNullOrEmpty($Assembly)) {
$asmInfo = [System.Reflection.Assembly]::LoadFrom($AssemblyFrom)
}
if ($null -eq $asmInfo) {
throw New-Object System.Management.Automation.ParameterBindingException 'The parameter ''Assembly'' or ''AssemblyFrom'' is mandatory.'
Write-Error 'The parameter ''Assembly'' or ''AssemblyFrom'' is mandatory.'
exit -403162398
}

$refAsmInfos = New-Object 'System.Collections.Generic.List[System.Reflection.Assembly]'
Expand All @@ -98,7 +104,23 @@ foreach ($refAsmName in $asmInfo.GetReferencedAssemblies()) {
$refAsmInfos.Add([System.Reflection.Assembly]::Load($refAsmName.FullName))
}
catch {
Write-Warning ($_ | Out-String)
if ([string]::IsNullOrEmpty($AssemblyFrom)) {
$candidateDir = $OutputPath
} else {
$candidateDir = [System.IO.Path]::GetDirectoryName($AssemblyFrom)
}
$refAsmPathWithoutExtension = [System.IO.Path]::Combine($candidateDir, $refAsmName.Name)
try {
$refAsmInfos.Add([System.Reflection.Assembly]::LoadFrom($refAsmPathWithoutExtension + ".dll"))
}
catch {
try {
$refAsmInfos.Add([System.Reflection.Assembly]::LoadFrom($refAsmPathWithoutExtension + ".exe"))
}
catch {
Write-Warning ($_ | Out-String)
}
}
}
}
$systemAsmInfo = [System.Reflection.Assembly]::LoadWithPartialName('System')
Expand All @@ -123,6 +145,11 @@ $fileMap = New-Object System.Configuration.ExeConfigurationFileMap
$fileMap.ExeConfigFilename = $Settings
$config = [System.Configuration.ConfigurationManager]::OpenMappedExeConfiguration($fileMap, [System.Configuration.ConfigurationUserLevel]::None)
$section = $config.GetSection("prig")
$unintendedSettings = @($section.Stubs | ? { $_.Target.Module.Assembly -ne $asmInfo })
if (0 -lt $unintendedSettings.Length) {
Write-Error ('Now the indirection settings for "{0}" is being analysed, but the settings for "{1}" was detected.' -f $asmInfo.FullName, $unintendedSettings[0].Target.Module.Assembly.FullName)
exit -1944878741
}

$workDir = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($Settings), (ConvertTo-PrigAssemblyName $asmInfo))
if (![string]::IsNullOrEmpty($workDir) -and ![IO.Directory]::Exists($workDir)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,90 @@
#

function Add-PrigAssembly {
<#
.SYNOPSIS
Creates the stub settings file for the specified assembly on the Package Manager Console.
.DESCRIPTION
This command adds the stub setting file that sets up the indirection settings for specified assembly to a project on the Package Manager Console.
Target project is the value that is selected as `Default project: ` on the Package Manager Console.
The stub setting file is named like `<assembly name>.<runtime version>.v<assembly version>.prig`.
After the file is added, you will get the confirmation message that the project has been modified externally, so reload the project.
.PARAMETER Assembly
A display name recognizing uniquely an assembly. Use this parameter if adding the stub setting file for a GAC registered assembly.
If it can't recognize uniquely, the error "Ambiguous match found" will be occurred. So, you have to specify a more detailed display name.
.PARAMETER AssemblyFrom
A full path recognizing uniquely an assembly. Use this parameter if adding the stub setting file for a GAC unregistered assembly.
Also, you have to change to the directory where specified assembly exists if using this parameter; otherwise referenced assemblies may not resolved.
.EXAMPLE
Add-PrigAssembly -Assembly "mscorlib, Version=4.0.0.0"
DESCRIPTION
-----------
This command adds the stub setting file for the assembly `mscorlib` to the target project.
.EXAMPLE
padd -as mscorlib
Ambiguous match found:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
DESCRIPTION
-----------
This is example that "You try to add the stub setting file for the assembly `mscorlib`, but the error 'Ambiguous match found' is occurred".
In this error, candidate assemblies are listed at the time. So, select again more detailed display name from them.
.EXAMPLE
C:\users\akira\documents\visual studio 2013\Projects\Demo\Demo\bin\Debug>dir
Directory: C:\users\akira\documents\visual studio 2013\Projects\Demo\Demo\bin\Debug
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2014/10/10 9:31 4096 DependentLibrary1.dll
-a--- 2014/10/10 9:31 7680 DependentLibrary1.pdb
-a--- 2014/10/10 9:31 4608 DependentLibrary2.dll
-a--- 2014/10/10 9:31 7680 DependentLibrary2.pdb
-a--- 2014/10/10 9:31 7680 DemoLibrary.dll
-a--- 2014/10/10 9:31 28160 DemoLibrary.pdb
C:\users\akira\documents\visual studio 2013\Projects\Demo\Demo\bin\Debug>padd -af (dir .\DemoLibrary.dll).FullName
DESCRIPTION
-----------
This command adds the stub setting file for the GAC unregistered assembly `DemoLibrary` to the target project.
If you specify `-AssemblyFrom` parameter, you have to execute this command in the directory that the target assembly exists like the example.
.INPUTS
System.String
.OUTPUTS
None
.NOTES
If you added the stub setting files once, it can only remove manually. Let's say you mistake the project that should be selected as `Default project: `.
In this case, you have to remove the tags `Reference`, `None`, `PreBuildEvent` that are matched the regular expression `\.prig"`.
Also, you can't set up the stub settings for multiple assemblies to one file. If you set up such setting, you will get the build error.
You can also refer to the Add-PrigAssembly command by its built-in alias, "PAdd".
.LINK
Find-IndirectionTarget
.LINK
Get-IndirectionStubSetting
.LINK
Invoke-Prig
#>

[CmdletBinding()]
param (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,113 @@
#

function Find-IndirectionTarget {
<#
.SYNOPSIS
Finds the targets to create the indirection setting on the Package Console Manager or PowerShell.
.DESCRIPTION
This command finds the methods that are satisfied the search condition on the Package Manager Console or PowerShell.
About the search way, first, it enumerates the members that are satisfied the following conditions from the specified parameter as `-InputObject`:
* a public member or a non-public member
* a instance member or a static member
* a only member declared at the level of the supplied type's hierarchy
* a constructor(containing a type constructor) or a method
* a non-abstract members
From them, it narrow the search to the results that are matched to specified the parameter `-Method`.
The string that is compared with `-Method` is same as the string that is listed as the results this command invoked.
.PARAMETER InputObject
An array of type or an array of string that can be recognized as a type.
"The string that can be recognized as a type" means that `Invoke-Expression ('[{0}]' -f $s)` - NOTE: $s is string - can evaluate to `Sytem.Type` object.
Therefore, you can specify the parameter like `datetime`, `system.reflection.assembly`, `([int])` and so on.
.PARAMETER Method
A search condition for the methods. You can use regular expression.
.EXAMPLE
Find-IndirectionTarget datetime '(today)|(now)'
Method
------
System.DateTime get_Now()
System.DateTime get_UtcNow()
System.DateTime get_Today()
DESCRIPTION
-----------
This command finds the members that contain the string `today` or `now` from the type `System.DateTime`.
.EXAMPLE
PS C:\>$asmInfo = [System.Reflection.Assembly]::LoadWithPartialName("System.Web")
PS C:\>$asmInfo.GetTypes() | ? { $_.Name -eq 'httpcontext' }
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False HttpContext System.Object
PS C:\>$asmInfo.GetTypes() | ? { $_.Name -eq 'httpcontext' } | pfind -m 'get_current\b'
Method
------
System.Web.HttpContext get_Current()
DESCRIPTION
-----------
In this example, first, it finds the types that is named `httpcontext` from the assembly `System.Web`.
Against the results, use this command, and find the members that are matched the regular expression `get_current\b`.
.EXAMPLE
C:\users\akira\documents\visual studio 2013\Projects\Demo\Demo\bin\Debug>ipmo ..\..\..\packages\Prig.0.0.0-alpha10\tools\Urasandesu.Prig
C:\users\akira\documents\visual studio 2013\Projects\Demo\Demo\bin\Debug>$asmInfo = [System.Reflection.Assembly]::LoadFrom((dir .\DemoLibrary.dll).FullName)
C:\users\akira\documents\visual studio 2013\Projects\Demo\Demo\bin\Debug>$asmInfo.GetTypes()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False Foo System.Object
C:\users\akira\documents\visual studio 2013\Projects\Demo\Demo\bin\Debug>$asmInfo.GetTypes() | pfind
Method
------
Void .ctor()
DESCRIPTION
-----------
This is the example that doesn't use the Package Manager Console but use PowerShell.
By the way, the Package Manager Console doesn't support nested prompt by its design. Therefore, there is the problem that it can never release the assemblies
if it loaded the assemblies to analyze indirection targets once. In the first place, the features that are used mundanely - such as autocompletion,
commands history and so on - are less functionality than PowerShell's.
I recommend that you always use PowerShell when analyzing the indirection targets.
.INPUTS
System.String, System.String[], System.Type, System.Type[]
.OUTPUTS
None, System.Reflection.MethodBase, System.Reflection.MethodBase[]
.NOTES
You have to import the module `Urasandesu.Prig` explicitly if you use this command on PowerShell.
The module `Urasandesu.Prig` is placed the directory `tools` of the package directory by NuGet when you installed Prig.
So, execute `Import-Module` it if you work on PowerShell.
You can also refer to the Find-IndirectionTarget command by its built-in alias, "PFind".
.LINK
Add-PrigAssembly
.LINK
Get-IndirectionStubSetting
.LINK
Invoke-Prig
#>

[CmdletBinding()]
param (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,79 @@
#

function Get-IndirectionStubSetting {
<#
.SYNOPSIS
Gets the indirection stub settings on the Package Manager Console or PowerShell.
.DESCRIPTION
This command creates XML tags that can be used as the indirection settings for the target method on the Package Manager Console or PowerShell, and gets them.
The indirection stub settings mean the tags that can be added to the stub setting file(`*.prig`) that is set up by the command `Add-PrigAssembly`.
In particular, the tag is `add`. You can insert it to between the tag `<stubs>...</stubs>` of the file.
Note that you have to typically generate unique name, and set to the tag(its attribute `name` and `alias`) in the type the target method is declared.
However, you can get easily such name by using this command.
The naming convention is similar to Microsoft Fakes's, but there is also a little different:
* The namespace that the stubs are located is the original namespace + `.Prig`.
` For example, the stubs for the types under `System` are located at the namespace `System.Prig`.
* The prefix of the stub is `P`(no conditions) or `PProxy`(specified instance of a class).
` For example, the stub for `System.DateTime` is `System.Prig.PDateTime`. However, the stub `PProxyDateTime` isn't generated, because it is a structure.
` The stub for `System.Net.HttpWebRequest` is `System.Net.Prig.PHttpWebRequest`. Also, `System.Net.Prig.PProxyHttpWebRequest` is generated, because it is a class.
See also [Code generation, compilation, and naming conventions in Microsoft Fakes](http://msdn.microsoft.com/en-us/library/hh708916.aspx).
The results are output as plain text, so I recommend that you use in combination with `clip` command.
.PARAMETER InputObject
A array of `System.Reflection.MethodBase` object which is target to get the indirection settings.
.EXAMPLE
PS C:\>pfind datetime _now | pget
<add name="NowGet" alias="NowGet">
<RuntimeMethodInfo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" z:Id="1" z:FactoryType="MemberInfoSerializationHolder" z:Type="System.Reflection.MemberInfoSerializationHolder" z:Assembly="0" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/System.Reflection">
<Name z:Id="2" z:Type="System.String" z:Assembly="0" xmlns="">get_Now</Name>
<AssemblyName z:Id="3" z:Type="System.String" z:Assembly="0" xmlns="">mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</AssemblyName>
<ClassName z:Id="4" z:Type="System.String" z:Assembly="0" xmlns="">System.DateTime</ClassName>
<Signature z:Id="5" z:Type="System.String" z:Assembly="0" xmlns="">System.DateTime get_Now()</Signature>
<Signature2 z:Id="6" z:Type="System.String" z:Assembly="0" xmlns="">System.DateTime get_Now()</Signature2>
<MemberType z:Id="7" z:Type="System.Int32" z:Assembly="0" xmlns="">8</MemberType>
<GenericArguments i:nil="true" xmlns="" />
</RuntimeMethodInfo>
</add>
PS C:\>pfind datetime _now | pget | clip
DESCRIPTION
-----------
This is the example that is used in combination with `Find-IndirectionTarget`.
Search the members that are matched to the regular expression `_now` from the type `System.DateTime`, and get the indirection stub settings.
When confirmed that, it has no problem. So, copy it to clipboard, and paste it to the stub settings file.
.INPUTS
System.Reflection.MethodBase, System.Reflection.MethodBase[]
.OUTPUTS
System.String
.NOTES
You have to import the module `Urasandesu.Prig` explicitly if you use this command on PowerShell.
The module `Urasandesu.Prig` is placed the directory `tools` of the package directory by NuGet when you installed Prig.
So, execute `Import-Module` it if you work on PowerShell.
You can also refer to the Get-IndirectionStubSetting command by its built-in alias, "PGet".
.LINK
Add-PrigAssembly
.LINK
Find-IndirectionTarget
.LINK
Invoke-Prig
#>

[CmdletBinding()]
param (
Expand Down
Loading

0 comments on commit a9c39cd

Please sign in to comment.