Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions .github/workflows/Action-Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ on: [pull_request]
env:
GH_TOKEN: ${{ github.token }}

permissions: {}

jobs:
ActionTestDefault:
name: Action-Test - [Default]
Expand All @@ -15,24 +17,13 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v4

- name: Checkout tests -> PSModuleTest
uses: actions/checkout@v4
with:
repository: PSModule/PSModuleTest
path: tests

- name: Delete outputs
shell: pwsh
run: |
Remove-Item -Path tests/outputs -Recurse -Force -Verbose

- name: Initialize environment
uses: PSModule/Initialize-PSModule@main

- name: Action-Test
uses: ./
with:
Name: PSModule
Name: PSModuleTest
Path: tests/src
ModulesOutputPath: tests/outputs/modules
DocsOutputPath: tests/outputs/docs
9 changes: 8 additions & 1 deletion .github/workflows/Linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ run-name: "Linter - [${{ github.event.pull_request.title }} #${{ github.event.pu

on: [pull_request]

permissions:
contents: read
packages: read
statuses: write # To report GitHub Actions status checks

jobs:
Lint:
name: Lint code base
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Lint code base
uses: github/super-linter@latest
uses: super-linter/super-linter@latest
env:
GITHUB_TOKEN: ${{ github.token }}
5 changes: 4 additions & 1 deletion scripts/helpers/Build/Build-PSModuleManifest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,11 @@ function Build-PSModuleManifest {
Show-FileContent -Path $outputManifestPath
Stop-LogGroup

Start-LogGroup 'Build manifest file - Result - After format'
Start-LogGroup 'Build manifest file - Format'
Set-ModuleManifest -Path $outputManifestPath
Stop-LogGroup

Start-LogGroup 'Build manifest file - Result - After format'
Show-FileContent -Path $outputManifestPath
Stop-LogGroup

Expand Down
4 changes: 4 additions & 0 deletions tests/src/PSModuleTest/PSModuleTest.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@{
ModuleVersion = '0.0.0'
RootModule = 'PSModuleTest.psm1'
}
73 changes: 73 additions & 0 deletions tests/src/PSModuleTest/PSModuleTest.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[Cmdletbinding()]
param()

Write-Verbose 'Importing subcomponents'
$Folders = 'init', 'classes', 'private', 'public'
# Import everything in these folders
Foreach ($Folder in $Folders) {
$Root = Join-Path -Path $PSScriptRoot -ChildPath $Folder
Write-Verbose "Processing folder: $Root"
if (Test-Path -Path $Root) {
Write-Verbose "Getting all files in $Root"
$Files = $null
$Files = Get-ChildItem -Path $Root -Include '*.ps1', '*.psm1' -Recurse
# dot source each file
foreach ($File in $Files) {
Write-Verbose "Importing $($File)"
Import-Module $File
Write-Verbose "Importing $($File): Done"
}
}
}

. "$PSScriptRoot\finally.ps1"

# Define the types to export with type accelerators.
$ExportableTypes = @(
[Book]
[BookList]
)

# Get the internal TypeAccelerators class to use its static methods.
$TypeAcceleratorsClass = [psobject].Assembly.GetType(
'System.Management.Automation.TypeAccelerators'
)
# Ensure none of the types would clobber an existing type accelerator.
# If a type accelerator with the same name exists, throw an exception.
$ExistingTypeAccelerators = $TypeAcceleratorsClass::Get
foreach ($Type in $ExportableTypes) {
if ($Type.FullName -in $ExistingTypeAccelerators.Keys) {
$Message = @(
"Unable to register type accelerator '$($Type.FullName)'"
'Accelerator already exists.'
) -join ' - '

throw [System.Management.Automation.ErrorRecord]::new(
[System.InvalidOperationException]::new($Message),
'TypeAcceleratorAlreadyExists',
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$Type.FullName
)
}
}
# Add type accelerators for every exportable type.
foreach ($Type in $ExportableTypes) {
$TypeAcceleratorsClass::Add($Type.FullName, $Type)
}
# Remove type accelerators when the module is removed.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
foreach ($Type in $ExportableTypes) {
$TypeAcceleratorsClass::Remove($Type.FullName)
}
}.GetNewClosure()

$Param = @{
Function = (Get-ChildItem -Path "$PSScriptRoot\public" -Include '*.ps1' -Recurse).BaseName
Variable = '*'
Cmdlet = '*'
Alias = '*'
}

Write-Verbose 'Exporting module members'

Export-ModuleMember @Param
Binary file added tests/src/PSModuleTest/assemblies/LsonLib.dll
Binary file not shown.
132 changes: 132 additions & 0 deletions tests/src/PSModuleTest/classes/Book.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
class Book {
# Class properties
[string] $Title
[string] $Author
[string] $Synopsis
[string] $Publisher
[datetime] $PublishDate
[int] $PageCount
[string[]] $Tags
# Default constructor
Book() { $this.Init(@{}) }
# Convenience constructor from hashtable
Book([hashtable]$Properties) { $this.Init($Properties) }
# Common constructor for title and author
Book([string]$Title, [string]$Author) {
$this.Init(@{Title = $Title; Author = $Author })
}
# Shared initializer method
[void] Init([hashtable]$Properties) {
foreach ($Property in $Properties.Keys) {
$this.$Property = $Properties.$Property
}
}
# Method to calculate reading time as 2 minutes per page
[timespan] GetReadingTime() {
if ($this.PageCount -le 0) {
throw 'Unable to determine reading time from page count.'
}
$Minutes = $this.PageCount * 2
return [timespan]::new(0, $Minutes, 0)
}
# Method to calculate how long ago a book was published
[timespan] GetPublishedAge() {
if (
$null -eq $this.PublishDate -or
$this.PublishDate -eq [datetime]::MinValue
) { throw 'PublishDate not defined' }

return (Get-Date) - $this.PublishDate
}
# Method to return a string representation of the book
[string] ToString() {
return "$($this.Title) by $($this.Author) ($($this.PublishDate.Year))"
}
}

class BookList {
# Static property to hold the list of books
static [System.Collections.Generic.List[Book]] $Books
# Static method to initialize the list of books. Called in the other
# static methods to avoid needing to explicit initialize the value.
static [void] Initialize() { [BookList]::Initialize($false) }
static [bool] Initialize([bool]$force) {
if ([BookList]::Books.Count -gt 0 -and -not $force) {
return $false
}

[BookList]::Books = [System.Collections.Generic.List[Book]]::new()

return $true
}
# Ensure a book is valid for the list.
static [void] Validate([book]$Book) {
$Prefix = @(
'Book validation failed: Book must be defined with the Title,'
'Author, and PublishDate properties, but'
) -join ' '
if ($null -eq $Book) { throw "$Prefix was null" }
if ([string]::IsNullOrEmpty($Book.Title)) {
throw "$Prefix Title wasn't defined"
}
if ([string]::IsNullOrEmpty($Book.Author)) {
throw "$Prefix Author wasn't defined"
}
if ([datetime]::MinValue -eq $Book.PublishDate) {
throw "$Prefix PublishDate wasn't defined"
}
}
# Static methods to manage the list of books.
# Add a book if it's not already in the list.
static [void] Add([Book]$Book) {
[BookList]::Initialize()
[BookList]::Validate($Book)
if ([BookList]::Books.Contains($Book)) {
throw "Book '$Book' already in list"
}

$FindPredicate = {
param([Book]$b)

$b.Title -eq $Book.Title -and
$b.Author -eq $Book.Author -and
$b.PublishDate -eq $Book.PublishDate
}.GetNewClosure()
if ([BookList]::Books.Find($FindPredicate)) {
throw "Book '$Book' already in list"
}

[BookList]::Books.Add($Book)
}
# Clear the list of books.
static [void] Clear() {
[BookList]::Initialize()
[BookList]::Books.Clear()
}
# Find a specific book using a filtering scriptblock.
static [Book] Find([scriptblock]$Predicate) {
[BookList]::Initialize()
return [BookList]::Books.Find($Predicate)
}
# Find every book matching the filtering scriptblock.
static [Book[]] FindAll([scriptblock]$Predicate) {
[BookList]::Initialize()
return [BookList]::Books.FindAll($Predicate)
}
# Remove a specific book.
static [void] Remove([Book]$Book) {
[BookList]::Initialize()
[BookList]::Books.Remove($Book)
}
# Remove a book by property value.
static [void] RemoveBy([string]$Property, [string]$Value) {
[BookList]::Initialize()
$Index = [BookList]::Books.FindIndex({
param($b)
$b.$Property -eq $Value
}.GetNewClosure())
if ($Index -ge 0) {
[BookList]::Books.RemoveAt($Index)
}
}
}
3 changes: 3 additions & 0 deletions tests/src/PSModuleTest/data/Config.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
RandomKey = 'RandomValue'
}
3 changes: 3 additions & 0 deletions tests/src/PSModuleTest/data/Settings.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
RandomSetting = 'RandomSettingValue'
}
3 changes: 3 additions & 0 deletions tests/src/PSModuleTest/finally.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Write-Verbose '------------------------------' -Verbose
Write-Verbose '--- THIS IS A LAST LOADER ---' -Verbose
Write-Verbose '------------------------------' -Verbose
37 changes: 37 additions & 0 deletions tests/src/PSModuleTest/formats/CultureInfo.Format.ps1xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<ViewDefinitions>
<View>
<Name>System.Globalization.CultureInfo</Name>
<ViewSelectedBy>
<TypeName>System.Globalization.CultureInfo</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Width>16</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>16</Width>
</TableColumnHeader>
<TableColumnHeader />
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>LCID</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>DisplayName</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
65 changes: 65 additions & 0 deletions tests/src/PSModuleTest/formats/Mygciview.Format.ps1xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<ViewDefinitions>
<View>
<Name>mygciview</Name>
<ViewSelectedBy>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
</ViewSelectedBy>
<GroupBy>
<PropertyName>PSParentPath</PropertyName>
</GroupBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>Mode</Label>
<Width>7</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>LastWriteTime</Label>
<Width>26</Width>
<Alignment>Right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>CreationTime</Label>
<Width>26</Width>
<Alignment>Right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Length</Label>
<Width>14</Width>
<Alignment>Right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Name</Label>
<Alignment>Left</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<Wrap />
<TableColumnItems>
<TableColumnItem>
<PropertyName>ModeWithoutHardLink</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>LastWriteTime</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>CreationTime</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Length</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
Loading