Skip to content

Commit

Permalink
🩹 [Patch]: Add tests and update linter (#37)
Browse files Browse the repository at this point in the history
## Description

- Add test data
- Update linter

## Type of change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [ ] 📖 [Docs]
- [ ] 🪲 [Fix]
- [x] 🩹 [Patch]
- [x] ⚠️ [Security fix]
- [ ] 🚀 [Feature]
- [ ] 🌟 [Breaking change]

## Checklist

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
  • Loading branch information
MariusStorhaug authored Mar 24, 2024
1 parent 7effee7 commit f53f0d6
Show file tree
Hide file tree
Showing 24 changed files with 522 additions and 14 deletions.
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

0 comments on commit f53f0d6

Please sign in to comment.