Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 4, 2026

Fix DatabasePermission.Equals() to compare both State and Permission properties

Summary

Fixed a bug where DatabasePermission.Equals() and ServerPermission.Equals() only compared the Permission property and ignored the State property. The methods incorrectly referenced a non-existent Grant property instead of the correct State property.

Changes Made

  • Set up build and test environment
  • Run existing unit tests for DatabasePermission to confirm the bug
  • Fix DatabasePermission.Equals() method to compare State property
  • Update DatabasePermission unit tests to expect correct behavior
  • Run tests to verify DatabasePermission fix
  • Fix ServerPermission.Equals() method (has same bug)
  • Update ServerPermission unit tests to expect correct behavior
  • Run tests to verify ServerPermission fix
  • Check if SqlDatabasePermission resource tests are affected
  • Run final verification tests
  • Add comprehensive test coverage for all State combinations
  • Add GetHashCode() override to both classes for hash-based collection compatibility
  • Fix misleading variable naming in ServerPermission tests
  • Simplify GetHashCode() implementation and remove TODO comment
  • Request code review (no issues found)

Test Results

  • ✅ All 64 unit tests pass for DatabasePermission and ServerPermission classes (including GetHashCode tests)
  • ✅ All 76 unit tests pass for dependent resources (SqlDatabasePermission and SqlPermission)
  • ✅ Code review completed with no issues

Fixes

Resolves issue #2386

Original prompt

This section details on the original issue you should resolve

<issue_title>DatabasePermission.Equals() only compares Permission property, ignores State property</issue_title>
<issue_description>## Description

The DatabasePermission.Equals() method has a bug where it only compares the Permission property and ignores the State property. This causes incorrect equality comparisons when two instances have the same Permission but different State values.

Current Behavior

When comparing two DatabasePermission instances:

  • Instance 1: State = 'Deny', Permission = 'select'
  • Instance 2: State = 'Grant', Permission = 'select'

The comparison returns true (equal) when it should return false (not equal).

Expected Behavior

The Equals() method should compare both the State and Permission properties to determine equality.

Impact

  • Tests currently assert the buggy behavior rather than the correct behavior
  • Future developers may not realize this is incorrect behavior
  • The bug becomes harder to track and fix over time

Affected Files

  • source/Classes/DatabasePermission.ps1 (or similar location for the class implementation)
  • tests/Unit/Classes/DatabasePermission.Tests.ps1 (lines 158-161)

Suggested Fix

  1. Update the Equals() method to compare both State and Permission properties
  2. Ensure GetHashCode() also covers both fields consistently
  3. Revert the test assertion to the correct expectation (Should -BeFalse)
  4. Add/adjust unit tests to cover both equal and not-equal cases

References

<agent_instructions>Make sure this is tested in the unit tests for the class, then fix the issue if the bug exist. After that fix the class-based resource's unit tests that depends on the class DatabasePermission.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.


This change is Reviewable

@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Fixed equality semantics in DatabasePermission and ServerPermission to compare both State and Permission, added consistent GetHashCode() implementations, updated unit tests accordingly, and changed Set-SqlDscServerPermission to only modify permission categories explicitly provided by parameters.

Changes

Cohort / File(s) Summary
Permission classes
source/Classes/002.DatabasePermission.ps1, source/Classes/002.ServerPermission.ps1
Updated Equals() to compare State and Permission (removed incorrect Grant reference). Added GetHashCode() overrides computing hash from State and sorted Permission items.
Unit tests
tests/Unit/Classes/DatabasePermission.Tests.ps1, tests/Unit/Classes/ServerPermission.Tests.ps1
Renamed test variables, added contexts asserting inequality for differing State values, added GetHashCode() assertions (equal vs different State/Permission), and expanded CompareTo() scenarios.
DSC command behavior
CHANGELOG.md, (implementation) Set-SqlDscServerPermission
Behavior changed: only process permission categories explicitly provided via parameters; unspecified categories are left unchanged.
Changelog
CHANGELOG.md
Documented equality/hashcode fixes and the Set-SqlDscServerPermission behavior change.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately and specifically describes the main changes: fixing Equals() methods and adding GetHashCode() overrides to DatabasePermission and ServerPermission classes.
Description check ✅ Passed The PR description comprehensively relates to the changeset, detailing the bug fix, changes made, test results, and resolution of issue #2386.
Linked Issues check ✅ Passed All objectives from issue #2391 are met: Equals() now compares State and Permission, GetHashCode() overrides added, unit tests updated to assert correct behavior, and fixes extended to ServerPermission.
Out of Scope Changes check ✅ Passed All changes are within scope of issue #2391: fixing equality bugs in DatabasePermission and ServerPermission, adding GetHashCode() overrides, updating tests, and fixing misleading variable naming in ServerPermission tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bffc1ab and 042eff9.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1
🚧 Files skipped from review as they are similar to previous changes (2)
  • source/Classes/002.ServerPermission.ps1
  • source/Classes/002.DatabasePermission.ps1
🧰 Additional context used
📓 Path-based instructions (3)
CHANGELOG.md

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-changelog.instructions.md)

CHANGELOG.md: Always update the Unreleased section in CHANGELOG.md
Use Keep a Changelog format in CHANGELOG.md
Describe notable changes briefly in CHANGELOG.md, ≤2 items per change type
Reference issues using format issue #<issue_number> in CHANGELOG.md
No empty lines between list items in same section of CHANGELOG.md
Skip adding entry if same change already exists in Unreleased section of CHANGELOG.md
No duplicate sections or items in Unreleased section of CHANGELOG.md

Always update CHANGELOG.md Unreleased section

Files:

  • CHANGELOG.md

⚙️ CodeRabbit configuration file

CHANGELOG.md: # Changelog Guidelines

  • Always update the Unreleased section in CHANGELOG.md
  • Use Keep a Changelog format
  • Describe notable changes briefly, ≤2 items per change type
  • Reference issues using format issue #<issue_number>
  • No empty lines between list items in same section
  • Skip adding entry if same change already exists in Unreleased section
  • No duplicate sections or items in Unreleased section

Files:

  • CHANGELOG.md
**/*.md

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-markdown.instructions.md)

**/*.md: Wrap lines at word boundaries when over 80 characters (except tables/code blocks)
Use 2 spaces for indentation in Markdown files
Use '1.' for all items in ordered lists (1/1/1 numbering style)
Disable MD013 rule by adding a comment for tables/code blocks exceeding 80 characters
Empty lines required before/after code blocks and headings (except before line 1)
Escape backslashes in file paths only (not in code blocks)
Code blocks must specify language identifiers
Format parameters using bold in Markdown documentation
Format values and literals using inline code in Markdown documentation
Format resource/module/product names using italic in Markdown documentation
Format commands/files/paths using inline code in Markdown documentation

Files:

  • CHANGELOG.md

⚙️ CodeRabbit configuration file

**/*.md: # Markdown Style Guidelines

  • Wrap lines at word boundaries when over 80 characters (except tables/code blocks)
  • Use 2 spaces for indentation
  • Use '1.' for all items in ordered lists (1/1/1 numbering style)
  • Disable MD013 rule by adding a comment for tables/code blocks exceeding 80 characters
  • Empty lines required before/after code blocks and headings (except before line 1)
  • Escape backslashes in file paths only (not in code blocks)
  • Code blocks must specify language identifiers

Text Formatting

  • Parameters: bold
  • Values/literals: inline code
  • Resource/module/product names: italic
  • Commands/files/paths: inline code

Files:

  • CHANGELOG.md
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

  • Command: Public command
  • Function: Private function
  • Resource: DSC class-based resource

Build & Test Workflow Requirements

  • Run PowerShell script files from repository root
  • Setup build and test environment (once per pwsh session): ./build.ps1 -Tasks noop
  • Build project before running tests: ./build.ps1 -Tasks build
  • Always run tests in new pwsh session: Invoke-Pester -Path @({test paths}) -Output Detailed

File Organization

  • Public commands: source/Public/{CommandName}.ps1
  • Private functions: source/Private/{FunctionName}.ps1
  • Classes: source/Classes/{DependencyGroupNumber}.{ClassName}.ps1
  • Enums: source/Enum/{DependencyGroupNumber}.{EnumName}.ps1
  • Unit tests: tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1
  • Integration tests: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1

Requirements

  • Follow instructions over existing code patterns
  • Follow PowerShell style and test guideline instructions strictly
  • Always update CHANGELOG.md Unreleased section
  • Localize all strings using string keys; remove any orphaned string keys
  • Check DscResource.Common before creating private functions
  • Separate reusable logic into private functions
  • DSC resources should always be created as class-based resources
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • CHANGELOG.md
🧠 Learnings (4)
📓 Common learnings
Learnt from: johlju
Repo: dsccommunity/SqlServerDsc PR: 2136
File: source/Public/Remove-SqlDscLogin.ps1:104-108
Timestamp: 2025-08-17T10:13:30.079Z
Learning: In SqlServerDsc unit tests, SMO object stubs (like Login objects) should have properly mocked Parent properties with correct Server stub types and valid InstanceName values, rather than handling null Parent scenarios in production code.
📚 Learning: 2025-11-27T17:58:08.884Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-changelog.instructions.md:0-0
Timestamp: 2025-11-27T17:58:08.884Z
Learning: Applies to CHANGELOG.md : No duplicate sections or items in Unreleased section of CHANGELOG.md

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-11-27T17:58:08.884Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-changelog.instructions.md:0-0
Timestamp: 2025-11-27T17:58:08.884Z
Learning: Applies to CHANGELOG.md : Skip adding entry if same change already exists in Unreleased section of CHANGELOG.md

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-11-27T17:58:08.884Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-changelog.instructions.md:0-0
Timestamp: 2025-11-27T17:58:08.884Z
Learning: Applies to CHANGELOG.md : Always update the Unreleased section in CHANGELOG.md

Applied to files:

  • CHANGELOG.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: dsccommunity.SqlServerDsc (Build Package Module)
  • GitHub Check: PSScriptAnalyzer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI and others added 2 commits January 4, 2026 09:28
- Fixed DatabasePermission.Equals() to compare State property instead of non-existent Grant property
- Fixed ServerPermission.Equals() to compare State property instead of non-existent Grant property
- Updated unit tests to expect correct behavior (Should -BeFalse when State differs)
- All unit tests pass for both classes and dependent resources

Co-authored-by: johlju <[email protected]>
- Added test cases for Grant vs GrantWithGrant comparison in DatabasePermission
- Added test cases for Grant vs GrantWithGrant comparison in ServerPermission
- All 58 unit tests pass for the permission classes
- All 76 unit tests pass for dependent resources

Co-authored-by: johlju <[email protected]>
@johlju johlju marked this pull request as ready for review January 4, 2026 09:30
@johlju johlju requested review from a team and johlju as code owners January 4, 2026 09:30
@johlju
Copy link
Member

johlju commented Jan 4, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copilot AI changed the title [WIP] Fix DatabasePermission.Equals() to compare State property Fix DatabasePermission and ServerPermission Equals() comparing non-existent Grant property Jan 4, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
source/Classes/002.DatabasePermission.ps1 (1)

180-196: Equals() fix correctly uses State; consider long‑term hashing alignment

The updated Equals() now gates the permission comparison on State, which correctly fixes the earlier bug where Grant was referenced instead. The type check plus State equality plus Compare-Object on Permission gives the expected semantics for value comparison.

As a follow‑up (not specific to this change), if DatabasePermission instances are ever used in hash-based collections, you may want to add/align a GetHashCode() override with the State + normalized Permission equality semantics to keep them consistent.

CHANGELOG.md (1)

235-246: Avoid duplicate ### Fixed sections under Unreleased

The new DatabasePermission/ServerPermission entries are accurate and properly reference [issue #2386], but they sit under a second ### Fixed heading within the [Unreleased] section. To align with the changelog guidelines (no duplicate sections per change type in Unreleased), consider moving these bullets under the existing ### Fixed at Line 173 and removing this extra heading.
As per changelog guidelines.

tests/Unit/Classes/ServerPermission.Tests.ps1 (1)

133-161: Test logic is correct; consider fixing variable naming in a follow-up.

The test correctly validates that ServerPermission objects with different State values (Deny vs Grant) are not equal.

The variable name $databasePermissionInstance on lines 138 and 149 is misleading since it creates a [ServerPermission] object, not [DatabasePermission]. This naming inconsistency exists throughout the file (also on lines 196, 210, etc.), so it's consistent with existing code but could be cleaned up in a future refactor.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4904751 and 8c77f5b.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
  • tests/Unit/Classes/ServerPermission.Tests.ps1
🧰 Additional context used
📓 Path-based instructions (14)
source/[cC]lasses/**/*.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-class-resource.instructions.md)

source/[cC]lasses/**/*.ps1: DSC class-based resources must be decorated with [DscResource(RunAsCredential = 'Optional')] or [DscResource(RunAsCredential = 'Mandatory')] based on requirements
DSC class-based resources must inherit from ResourceBase class from the DscResource.Base module
DSC class-based resources must use [Nullable[{FullTypeName}]] syntax for value-type properties (e.g., [Nullable[System.Int32]])
DSC class-based resources must implement a required constructor with signature ResourceName () : base ($PSScriptRoot) and populate $this.ExcludeDscProperties array
DSC class-based resources must implement required methods: Get(), Test(), Set(), GetCurrentState(), and Modify() following the specified pattern
DSC class-based resources may optionally implement methods: AssertProperties() and NormalizeProperties() following the specified pattern
DSC class-based resources must include comment-based help with .DESCRIPTION section containing Requirements and Known issues sections with a link to all open issues on GitHub
DSC class-based resources must use try/catch blocks for exception handling in classes
DSC class-based resources must use New-*Exception commands (such as New-InvalidDataException, New-ArgumentException, New-InvalidOperationException, New-ObjectNotFoundException, New-InvalidResultException, New-NotImplementedException) instead of throw for terminating errors in classes

Files:

  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1

⚙️ CodeRabbit configuration file

source/[cC]lasses/**/*.ps1: # DSC Class-Based Resource Guidelines

Applies to: Classes with [DscResource(...)] decoration only.

Requirements

  • File: source/Classes/020.{ResourceName}.ps1
  • Decoration: [DscResource(RunAsCredential = 'Optional')] (replace with 'Mandatory' if required)
  • Inheritance: Must inherit ResourceBase (part of module DscResource.Base)
  • $this.localizedData hashtable auto-populated by ResourceBase from localization file
  • value-type properties: Use [Nullable[{FullTypeName}]] (e.g., [Nullable[System.Int32]])

Required constructor

MyResourceName () : base ($PSScriptRoot)
{
    # Property names where state cannot be enforced, e.g. IsSingleInstance, Force
    $this.ExcludeDscProperties = @()
}

Required Method Pattern

[MyResourceName] Get()
{
    # Call base implementation to get current state
    $currentState = ([ResourceBase] $this).Get()

    # If needed, post-processing on current state that can not be handled by GetCurrentState()

    return $currentState
}

[System.Boolean] Test()
{
    # Call base implementation to test current state
    $inDesiredState = ([ResourceBase] $this).Test()

    # If needed, post-processing on test result that can not be handled by base Test()

    return $inDesiredState
}

[void] Set()
{
    # Call base implementation to set desired state
    ([ResourceBase] $this).Set()

    # If needed, additional state changes that can not be handled by Modify()
}

hidden [System.Collections.Hashtable] GetCurrentState([System.Collections.Hashtable] $properties)
{
    # Always return current state as hashtable, $properties contains key properties
}

hidden [void] Modify([System.Collections.Hashtable] $properties)
{
    # Always set desired state, $properties contain those that must change state
}

Optional Method Pattern

hidden [void] AssertProperties([System.Collections.Hashtable] $properties)
{
    # Validate user-provided properties, $p...

Files:

  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1
source/**/*.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-localization.instructions.md)

source/**/*.ps1: Localize all Write-Debug, Write-Verbose, Write-Error, Write-Warning and $PSCmdlet.ThrowTerminatingError() messages in PowerShell scripts
Use localized string keys from $script:localizedData, not hardcoded strings, in diagnostic messages
Reference localized strings using the syntax: Write-Verbose -Message ($script:localizedData.KeyName -f $value1)

Localize all strings using string keys; remove any orphaned string keys

Files:

  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1

⚙️ CodeRabbit configuration file

source/**/*.ps1: # Localization Guidelines

Requirements

  • Localize all Write-Debug, Write-Verbose, Write-Error, Write-Warning and $PSCmdlet.ThrowTerminatingError() messages
  • Use localized string keys, not hardcoded strings
  • Assume $script:localizedData is available

String Files

  • Commands/functions: source/en-US/{MyModuleName}.strings.psd1
  • Class resources: source/en-US/{ResourceClassName}.strings.psd1

Key Naming Patterns

  • Format: Verb_FunctionName_Action (underscore separators), e.g. Get_Database_ConnectingToDatabase

String Format

ConvertFrom-StringData @'
    KeyName = Message with {0} placeholder. (PREFIX0001)
'@

String IDs

  • Format: (PREFIX####)
  • PREFIX: First letter of each word in class or function name (SqlSetup → SS, Get-SqlDscDatabase → GSDD)
  • Number: Sequential from 0001

Usage

Write-Verbose -Message ($script:localizedData.KeyName -f $value1)

Files:

  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1
source/Classes/*.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines.instructions.md)

source/Classes/*.ps1: Classes should be located in source/Classes/{DependencyGroupNumber}.{ClassName}.ps1
DSC resources should always be created as class-based resources

Files:

  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1
**/*.{ps1,psm1,psd1}

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-powershell.instructions.md)

**/*.{ps1,psm1,psd1}: Use descriptive names (3+ characters, no abbreviations) for functions, parameters, variables, and classes
Functions: Use PascalCase with Verb-Noun format using approved verbs
Parameters: Use PascalCase naming
Variables: Use camelCase naming
Keywords: Use lower-case
Classes: Use PascalCase naming
Include scope for script/global/environment variables: $script:, $global:, $env:
Use 4 spaces for indentation (no tabs)
Use one space around operators: $a = 1 + 2
Use one space between type and variable: [String] $name
Use one space between keyword and parenthesis: if ($condition)
No spaces on empty lines
Limit lines to 120 characters
Place newline before opening brace (except variable assignments)
Place one newline after opening brace
Place two newlines after closing brace (one if followed by another brace or continuation)
Use single quotes unless variable expansion is needed: 'text' vs "text $variable"
For single-line arrays use: @('one', 'two', 'three')
For multi-line arrays: place each element on separate line with proper indentation
Do not use the unary comma operator (,) in return statements to force an array
For empty hashtables use: @{}
For hashtables: place each property on separate line with proper indentation and use PascalCase for property names
Single-line comments: use # Comment format (capitalized, on own line)
Multi-line comments: use <# Comment #> format (opening and closing brackets on own line with indented text)
No commented-out code
Always add comment-based help to all functions and scripts with SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, and EXAMPLE sections before function/class
Comment-based help indentation: keywords 4 spaces, text 8 spaces
Include examples in comment-based help for all parameter sets and combinations
INPUTS section in comment-based help: List each pipeline-accepted type as inline code with a 1-line description, repeat keyword for each input type, specify None. if there are no inp...

Files:

  • source/Classes/002.DatabasePermission.ps1
  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • source/Classes/002.ServerPermission.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
**/[0-9][0-9][0-9].*.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-powershell.instructions.md)

Class files: Use ###.ClassName.ps1 format (e.g., 001.SqlReason.ps1, 004.StartupParameters.ps1)

Files:

  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

  • Command: Public command
  • Function: Private function
  • Resource: DSC class-based resource

Build & Test Workflow Requirements

  • Run PowerShell script files from repository root
  • Setup build and test environment (once per pwsh session): ./build.ps1 -Tasks noop
  • Build project before running tests: ./build.ps1 -Tasks build
  • Always run tests in new pwsh session: Invoke-Pester -Path @({test paths}) -Output Detailed

File Organization

  • Public commands: source/Public/{CommandName}.ps1
  • Private functions: source/Private/{FunctionName}.ps1
  • Classes: source/Classes/{DependencyGroupNumber}.{ClassName}.ps1
  • Enums: source/Enum/{DependencyGroupNumber}.{EnumName}.ps1
  • Unit tests: tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1
  • Integration tests: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1

Requirements

  • Follow instructions over existing code patterns
  • Follow PowerShell style and test guideline instructions strictly
  • Always update CHANGELOG.md Unreleased section
  • Localize all strings using string keys; remove any orphaned string keys
  • Check DscResource.Common before creating private functions
  • Separate reusable logic into private functions
  • DSC resources should always be created as class-based resources
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • source/Classes/002.DatabasePermission.ps1
  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • source/Classes/002.ServerPermission.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
  • CHANGELOG.md
{**/*.ps1,**/*.psm1,**/*.psd1}

⚙️ CodeRabbit configuration file

{**/*.ps1,**/*.psm1,**/*.psd1}: # PowerShell Guidelines

Naming

  • Use descriptive names (3+ characters, no abbreviations)
  • Functions: PascalCase with Verb-Noun format using approved verbs
  • Parameters: PascalCase
  • Variables: camelCase
  • Keywords: lower-case
  • Classes: PascalCase
  • Include scope for script/global/environment variables: $script:, $global:, $env:

File naming

  • Class files: ###.ClassName.ps1 format (e.g. 001.SqlReason.ps1, 004.StartupParameters.ps1)

Formatting

Indentation & Spacing

  • Use 4 spaces (no tabs)
  • One space around operators: $a = 1 + 2
  • One space between type and variable: [String] $name
  • One space between keyword and parenthesis: if ($condition)
  • No spaces on empty lines
  • Try to limit lines to 120 characters

Braces

  • Newline before opening brace (except variable assignments)
  • One newline after opening brace
  • Two newlines after closing brace (one if followed by another brace or continuation)

Quotes

  • Use single quotes unless variable expansion is needed: 'text' vs "text $variable"

Arrays

  • Single line: @('one', 'two', 'three')
  • Multi-line: each element on separate line with proper indentation
  • Do not use the unary comma operator (,) in return statements to force
    an array

Hashtables

  • Empty: @{}
  • Each property on separate line with proper indentation
  • Properties: Use PascalCase

Comments

  • Single line: # Comment (capitalized, on own line)
  • Multi-line: <# Comment #> format (opening and closing brackets on own line), and indent text
  • No commented-out code

Comment-based help

  • Always add comment-based help to all functions and scripts
  • Comment-based help: SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, EXAMPLE sections before function/class
  • Comment-based help indentation: keywords 4 spaces, text 8 spaces
  • Include examples for all parameter sets and combinations
  • INPUTS: List each pipeline‑accepted type as inline code with a 1‑line description...

Files:

  • source/Classes/002.DatabasePermission.ps1
  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • source/Classes/002.ServerPermission.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
**/*.[Tt]ests.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-pester.instructions.md)

**/*.[Tt]ests.ps1: All public commands, private functions and classes must have unit tests
All public commands and class-based resources must have integration tests
Use Pester v5 syntax only
Test code only inside Describe blocks
Assertions only in It blocks
Never test verbose messages, debug messages or parameter binding behavior
Pass all mandatory parameters to avoid prompts
Inside It blocks, assign unused return objects to $null (unless part of pipeline)
Tested entity must be called from within the It blocks
Keep results and assertions in same It block
Avoid try-catch-finally for cleanup, use AfterAll or AfterEach
Avoid unnecessary remove/recreate cycles
One Describe block per file matching the tested entity name
Context descriptions start with 'When'
It descriptions start with 'Should', must not contain 'when'
Mock variables prefix: 'mock'
Public commands: Never use InModuleScope (unless retrieving localized strings or creating an object using an internal class)
Private functions/class resources: Always use InModuleScope
Each class method = separate Context block
Each scenario = separate Context block
Use nested Context blocks for complex scenarios
Mocking in BeforeAll (BeforeEach only when required)
Setup/teardown in BeforeAll,BeforeEach/AfterAll,AfterEach close to usage
Spacing between blocks, arrange, act, and assert for readability
PascalCase: Describe, Context, It, Should, BeforeAll, BeforeEach, AfterAll, AfterEach
Use -BeTrue/-BeFalse never -Be $true/-Be $false
Never use Assert-MockCalled, use Should -Invoke instead
No Should -Not -Throw - invoke commands directly
Never add an empty -MockWith block
Omit -MockWith when returning $null
Set $PSDefaultParameterValues for Mock:ModuleName, Should:ModuleName, InModuleScope:ModuleName
Omit -ModuleName parameter on Pester commands
Never use Mock inside InModuleScope-block
Never use param() inside -MockWith scriptblock...

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1

⚙️ CodeRabbit configuration file

**/*.[Tt]ests.ps1: # Tests Guidelines

Core Requirements

  • All public commands, private functions and classes must have unit tests
  • All public commands and class-based resources must have integration tests
  • Use Pester v5 syntax only
  • Test code only inside Describe blocks
  • Assertions only in It blocks
  • Never test verbose messages, debug messages or parameter binding behavior
  • Pass all mandatory parameters to avoid prompts

Requirements

  • Inside It blocks, assign unused return objects to $null (unless part of pipeline)
  • Tested entity must be called from within the It blocks
  • Keep results and assertions in same It block
  • Avoid try-catch-finally for cleanup, use AfterAll or AfterEach
  • Avoid unnecessary remove/recreate cycles

Naming

  • One Describe block per file matching the tested entity name
  • Context descriptions start with 'When'
  • It descriptions start with 'Should', must not contain 'when'
  • Mock variables prefix: 'mock'

Structure & Scope

  • Public commands: Never use InModuleScope (unless retrieving localized strings or creating an object using an internal class)
  • Private functions/class resources: Always use InModuleScope
  • Each class method = separate Context block
  • Each scenario = separate Context block
  • Use nested Context blocks for complex scenarios
  • Mocking in BeforeAll (BeforeEach only when required)
  • Setup/teardown in BeforeAll,BeforeEach/AfterAll,AfterEach close to usage
  • Spacing between blocks, arrange, act, and assert for readability

Syntax Rules

  • PascalCase: Describe, Context, It, Should, BeforeAll, BeforeEach, AfterAll, AfterEach
  • Use -BeTrue/-BeFalse never -Be $true/-Be $false
  • Never use Assert-MockCalled, use Should -Invoke instead
  • No Should -Not -Throw - invoke commands directly
  • Never add an empty -MockWith block
  • Omit -MockWith when returning $null
  • Set $PSDefaultParameterValues for Mock:ModuleName, Should:ModuleName, `...

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
tests/Unit/Classes/*.[Tt]ests.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-pester.instructions.md)

Class resources: tests/Unit/Classes/{Name}.Tests.ps1

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
tests/Unit/**/*.Tests.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines.instructions.md)

Unit tests should be located in tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
tests/[Uu]nit/**/*.[Tt]ests.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-unit-tests.instructions.md)

tests/[Uu]nit/**/*.[Tt]ests.ps1: Test with localized strings using InModuleScope -ScriptBlock { $script:localizedData.Key } in Pester unit tests
Mock files using the $TestDrive variable (path to the test drive) in Pester unit tests
All public commands require parameter set validation tests in unit tests
Use the exact Pester test setup block with BeforeDiscovery, BeforeAll, and AfterAll blocks before Describe in unit tests, including DscResource.Test module import and PSDefaultParameterValues configuration
Use parameter set validation test template with Get-Command and ParameterSets property, supporting both single and multiple parameter sets via -ForEach array in Pester unit tests
Use parameter properties test template with Get-Command to validate individual parameter attributes (e.g., Mandatory flag) in Pester unit tests

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1

⚙️ CodeRabbit configuration file

tests/[Uu]nit/**/*.[Tt]ests.ps1: # Unit Tests Guidelines

  • Test with localized strings: Use InModuleScope -ScriptBlock { $script:localizedData.Key }
  • Mock files: Use $TestDrive variable (path to the test drive)
  • All public commands require parameter set validation tests
  • After modifying classes, always run tests in new session (for changes to take effect)

Test Setup Requirements

Use this exact setup block before Describe:

[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')]
param ()

BeforeDiscovery {
    try
    {
        if (-not (Get-Module -Name 'DscResource.Test'))
        {
            # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task.
            if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
            {
                # Redirect all streams to $null, except the error stream (stream 2)
                & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null
            }

            # If the dependencies have not been resolved, this will throw an error.
            Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
        }
    }
    catch [System.IO.FileNotFoundException]
    {
        throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks noop" first.'
    }
}

BeforeAll {
    $script:moduleName = '{MyModuleName}'

    Import-Module -Name $script:moduleName -ErrorAction 'Stop'

    $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName
    $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName
    $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName
}

AfterAll {
    $PSDefaultParameterValues.Remove('InModuleScope:ModuleName')
    $PSDefaultParameterValues.Remove('Mock:ModuleName')
   ...

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
**/tests/Unit/**/*.ps1

📄 CodeRabbit inference engine (.github/instructions/SqlServerDsc-guidelines.instructions.md)

**/tests/Unit/**/*.ps1: Unit tests must use SMO stub types from SMO.cs, never mock SMO types
Unit tests must add $env:SqlServerDscCI = $true in BeforeAll block and remove in AfterAll block
Load SMO stub types from SMO.cs in unit test files using Add-Type -Path "$PSScriptRoot/../Stubs/SMO.cs"

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
CHANGELOG.md

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-changelog.instructions.md)

CHANGELOG.md: Always update the Unreleased section in CHANGELOG.md
Use Keep a Changelog format in CHANGELOG.md
Describe notable changes briefly in CHANGELOG.md, ≤2 items per change type
Reference issues using format issue #<issue_number> in CHANGELOG.md
No empty lines between list items in same section of CHANGELOG.md
Skip adding entry if same change already exists in Unreleased section of CHANGELOG.md
No duplicate sections or items in Unreleased section of CHANGELOG.md

Always update CHANGELOG.md Unreleased section

Files:

  • CHANGELOG.md

⚙️ CodeRabbit configuration file

CHANGELOG.md: # Changelog Guidelines

  • Always update the Unreleased section in CHANGELOG.md
  • Use Keep a Changelog format
  • Describe notable changes briefly, ≤2 items per change type
  • Reference issues using format issue #<issue_number>
  • No empty lines between list items in same section
  • Skip adding entry if same change already exists in Unreleased section
  • No duplicate sections or items in Unreleased section

Files:

  • CHANGELOG.md
**/*.md

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-markdown.instructions.md)

**/*.md: Wrap lines at word boundaries when over 80 characters (except tables/code blocks)
Use 2 spaces for indentation in Markdown files
Use '1.' for all items in ordered lists (1/1/1 numbering style)
Disable MD013 rule by adding a comment for tables/code blocks exceeding 80 characters
Empty lines required before/after code blocks and headings (except before line 1)
Escape backslashes in file paths only (not in code blocks)
Code blocks must specify language identifiers
Format parameters using bold in Markdown documentation
Format values and literals using inline code in Markdown documentation
Format resource/module/product names using italic in Markdown documentation
Format commands/files/paths using inline code in Markdown documentation

Files:

  • CHANGELOG.md

⚙️ CodeRabbit configuration file

**/*.md: # Markdown Style Guidelines

  • Wrap lines at word boundaries when over 80 characters (except tables/code blocks)
  • Use 2 spaces for indentation
  • Use '1.' for all items in ordered lists (1/1/1 numbering style)
  • Disable MD013 rule by adding a comment for tables/code blocks exceeding 80 characters
  • Empty lines required before/after code blocks and headings (except before line 1)
  • Escape backslashes in file paths only (not in code blocks)
  • Code blocks must specify language identifiers

Text Formatting

  • Parameters: bold
  • Values/literals: inline code
  • Resource/module/product names: italic
  • Commands/files/paths: inline code

Files:

  • CHANGELOG.md
🧠 Learnings (21)
📚 Learning: 2026-01-01T11:57:15.286Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/SqlServerDsc-guidelines.instructions.md:0-0
Timestamp: 2026-01-01T11:57:15.286Z
Learning: Applies to **/tests/Unit/**/*.ps1 : Unit tests must add `$env:SqlServerDscCI = $true` in `BeforeAll` block and remove in `AfterAll` block

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Use nested `Context` blocks for complex scenarios

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to tests/Unit/Private/*.[Tt]ests.ps1 : Private functions: `tests/Unit/Private/{Name}.Tests.ps1`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Each scenario = separate `Context` block

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Each class method = separate `Context` block

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to tests/Unit/Public/*.[Tt]ests.ps1 : Public commands: `tests/Unit/Public/{Name}.Tests.ps1`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-12-30T15:15:25.261Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-integration-tests.instructions.md:0-0
Timestamp: 2025-12-30T15:15:25.261Z
Learning: Applies to tests/[iI]ntegration/**/*.[iI]ntegration.[tT]ests.ps1 : Integration tests must cover all scenarios and code paths

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-08-17T10:13:30.079Z
Learnt from: johlju
Repo: dsccommunity/SqlServerDsc PR: 2136
File: source/Public/Remove-SqlDscLogin.ps1:104-108
Timestamp: 2025-08-17T10:13:30.079Z
Learning: In SqlServerDsc unit tests, SMO object stubs (like Login objects) should have properly mocked Parent properties with correct Server stub types and valid InstanceName values, rather than handling null Parent scenarios in production code.

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Assertions only in `It` blocks

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-12-30T15:15:25.261Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-integration-tests.instructions.md:0-0
Timestamp: 2025-12-30T15:15:25.261Z
Learning: Applies to tests/[iI]ntegration/**/*.[iI]ntegration.[tT]ests.ps1 : Avoid using `ExpectedMessage` parameter for `Should -Throw` assertions in integration tests

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Never use `Mock` inside `InModuleScope`-block

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Never use `Assert-MockCalled`, use `Should -Invoke` instead

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Omit `-MockWith` when returning `$null`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-09-25T16:38:08.867Z
Learnt from: johlju
Repo: dsccommunity/ActiveDirectoryDsc PR: 741
File: tests/Integration/MSFT_ADReadOnlyDomainControllerAccount.Integration.Tests.ps1:102-104
Timestamp: 2025-09-25T16:38:08.867Z
Learning: The PowerShell guideline "Use -BeTrue/-BeFalse; never use -Be $true/-Be $false" applies only when the actual return value is a boolean. When a cmdlet returns string values like 'True' or 'False', Should -Be 'True' is the appropriate assertion.

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2026-01-01T11:57:15.286Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/SqlServerDsc-guidelines.instructions.md:0-0
Timestamp: 2026-01-01T11:57:15.286Z
Learning: Applies to **/tests/Integration/**/*.ps1 : Integration tests must use `Disconnect-SqlDscDatabaseEngine` after `Connect-SqlDscDatabaseEngine`

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : `Context` descriptions start with 'When'

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2026-01-01T11:57:15.286Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/SqlServerDsc-guidelines.instructions.md:0-0
Timestamp: 2026-01-01T11:57:15.286Z
Learning: Applies to **/tests/Integration/**/*.ps1 : Integration tests must use `Connect-SqlDscDatabaseEngine` for SQL Server DB session with correct CI credentials

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : PascalCase: `Describe`, `Context`, `It`, `Should`, `BeforeAll`, `BeforeEach`, `AfterAll`, `AfterEach`

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Mocking in `BeforeAll` (`BeforeEach` only when required)

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Use `-BeTrue`/`-BeFalse` never `-Be $true`/`-Be $false`

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:58:08.884Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-changelog.instructions.md:0-0
Timestamp: 2025-11-27T17:58:08.884Z
Learning: Applies to CHANGELOG.md : Describe notable changes briefly in CHANGELOG.md, ≤2 items per change type

Applied to files:

  • CHANGELOG.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: PSScriptAnalyzer
  • GitHub Check: dsccommunity.SqlServerDsc (Build Package Module)
🔇 Additional comments (4)
tests/Unit/Classes/DatabasePermission.Tests.ps1 (2)

133-161: New test context correctly validates State-based inequality.

The test properly verifies that DatabasePermission objects with State = 'Deny' and State = 'Grant' are not equal, which validates the bug fix in the Equals() method.


163-191: Test coverage for Grant vs GrantWithGrant looks good.

This context correctly tests the second State combination to ensure inequality is properly detected.

source/Classes/002.ServerPermission.ps1 (1)

112-128: Correct fix for the State property comparison.

The change from comparing the non-existent Grant property to the actual State property correctly fixes the equality logic. Previously, comparing undefined properties would always return $true (since $null -eq $null), causing incorrect equality results.

tests/Unit/Classes/ServerPermission.Tests.ps1 (1)

163-191: Test coverage for Grant vs GrantWithGrant is correct.

This context properly tests that objects with State = 'Grant' and State = 'GrantWithGrant' are not considered equal, validating the fix to the Equals() method.

@johlju
Copy link
Member

johlju commented Jan 4, 2026

@copilot can we resolve this too?

  1. As a follow‑up (not specific to this change), if DatabasePermission instances are ever used in hash-based collections, you may want to add/align a GetHashCode() override with the State + normalized Permission equality semantics to keep them consistent. Same in ServerPermission?

  2. tests/Unit/Classes/ServerPermission.Tests.ps1: The variable name $databasePermissionInstance on lines 138 and 149 is misleading since it creates a [ServerPermission] object, not [DatabasePermission]. This naming inconsistency exists throughout the file (also on lines 196, 210, etc.), so it's consistent with existing code but could be cleaned up in a future refactor.

- Added GetHashCode() override to DatabasePermission and ServerPermission to align with Equals() semantics
- Hash code is based on State and sorted Permission values for consistent behavior
- Fixed misleading variable naming in ServerPermission.Tests.ps1 (42 instances)
- Added comprehensive unit tests for GetHashCode() method in both classes
- All 64 unit tests pass (32 per class)
- All 76 dependent resource tests pass

Co-authored-by: johlju <[email protected]>
Copy link
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot can we resolve this too?

  1. As a follow‑up (not specific to this change), if DatabasePermission instances are ever used in hash-based collections, you may want to add/align a GetHashCode...

Done in commit bffc1ab. Both issues have been resolved:

  1. Added GetHashCode() override to both DatabasePermission and ServerPermission classes. The implementation uses State and sorted Permission values to ensure consistent hash codes for equal objects.

  2. Fixed the misleading variable naming in ServerPermission.Tests.ps1 - all 42 instances of $databasePermissionInstance have been renamed to $serverPermissionInstance.

Added comprehensive unit tests for GetHashCode() covering equal objects, different State, and different Permission scenarios. All 64 unit tests pass.

Copilot AI changed the title Fix DatabasePermission and ServerPermission Equals() comparing non-existent Grant property Fix DatabasePermission and ServerPermission Equals() and add GetHashCode() override Jan 4, 2026
@johlju
Copy link
Member

johlju commented Jan 4, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Member

@johlju johlju left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

@johlju reviewed 5 files and all commit messages, and made 1 comment.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on @copilot[bot]).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
source/Classes/002.DatabasePermission.ps1 (1)

198-210: GetHashCode() implementation is correct and aligns with Equals() semantics.

The method properly combines State with sorted Permission values using XOR, ensuring consistent hash codes for equal objects regardless of Permission ordering.

Optional: Initialize hashCode directly

The initial assignment to 0 on line 200 is immediately overwritten on line 202. Consider initializing directly:

 [System.Int32] GetHashCode()
 {
-    [System.Int32] $hashCode = 0
-
-    $hashCode = $this.State.GetHashCode()
+    [System.Int32] $hashCode = $this.State.GetHashCode()

     foreach ($permission in ($this.Permission | Sort-Object))
     {
         $hashCode = $hashCode -bxor $permission.GetHashCode()
     }

     return $hashCode
 }
source/Classes/002.ServerPermission.ps1 (1)

130-147: GetHashCode() implementation is correct and consistent with DatabasePermission.

The method properly combines State with sorted Permission values using XOR. The TODO comment appropriately notes the code duplication between DatabasePermission and ServerPermission.

Optional: Initialize hashCode directly

Same minor optimization as DatabasePermission - the initial assignment to 0 on line 137 is immediately overwritten on line 139:

 [System.Int32] GetHashCode()
 {
-    [System.Int32] $hashCode = 0
-
-    $hashCode = $this.State.GetHashCode()
+    [System.Int32] $hashCode = $this.State.GetHashCode()

     foreach ($permission in ($this.Permission | Sort-Object))
     {
         $hashCode = $hashCode -bxor $permission.GetHashCode()
     }

     return $hashCode
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c77f5b and bffc1ab.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • source/Classes/002.DatabasePermission.ps1
  • source/Classes/002.ServerPermission.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
  • tests/Unit/Classes/ServerPermission.Tests.ps1
🧰 Additional context used
📓 Path-based instructions (14)
source/[cC]lasses/**/*.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-class-resource.instructions.md)

source/[cC]lasses/**/*.ps1: DSC class-based resources must be decorated with [DscResource(RunAsCredential = 'Optional')] or [DscResource(RunAsCredential = 'Mandatory')] based on requirements
DSC class-based resources must inherit from ResourceBase class from the DscResource.Base module
DSC class-based resources must use [Nullable[{FullTypeName}]] syntax for value-type properties (e.g., [Nullable[System.Int32]])
DSC class-based resources must implement a required constructor with signature ResourceName () : base ($PSScriptRoot) and populate $this.ExcludeDscProperties array
DSC class-based resources must implement required methods: Get(), Test(), Set(), GetCurrentState(), and Modify() following the specified pattern
DSC class-based resources may optionally implement methods: AssertProperties() and NormalizeProperties() following the specified pattern
DSC class-based resources must include comment-based help with .DESCRIPTION section containing Requirements and Known issues sections with a link to all open issues on GitHub
DSC class-based resources must use try/catch blocks for exception handling in classes
DSC class-based resources must use New-*Exception commands (such as New-InvalidDataException, New-ArgumentException, New-InvalidOperationException, New-ObjectNotFoundException, New-InvalidResultException, New-NotImplementedException) instead of throw for terminating errors in classes

Files:

  • source/Classes/002.ServerPermission.ps1
  • source/Classes/002.DatabasePermission.ps1

⚙️ CodeRabbit configuration file

source/[cC]lasses/**/*.ps1: # DSC Class-Based Resource Guidelines

Applies to: Classes with [DscResource(...)] decoration only.

Requirements

  • File: source/Classes/020.{ResourceName}.ps1
  • Decoration: [DscResource(RunAsCredential = 'Optional')] (replace with 'Mandatory' if required)
  • Inheritance: Must inherit ResourceBase (part of module DscResource.Base)
  • $this.localizedData hashtable auto-populated by ResourceBase from localization file
  • value-type properties: Use [Nullable[{FullTypeName}]] (e.g., [Nullable[System.Int32]])

Required constructor

MyResourceName () : base ($PSScriptRoot)
{
    # Property names where state cannot be enforced, e.g. IsSingleInstance, Force
    $this.ExcludeDscProperties = @()
}

Required Method Pattern

[MyResourceName] Get()
{
    # Call base implementation to get current state
    $currentState = ([ResourceBase] $this).Get()

    # If needed, post-processing on current state that can not be handled by GetCurrentState()

    return $currentState
}

[System.Boolean] Test()
{
    # Call base implementation to test current state
    $inDesiredState = ([ResourceBase] $this).Test()

    # If needed, post-processing on test result that can not be handled by base Test()

    return $inDesiredState
}

[void] Set()
{
    # Call base implementation to set desired state
    ([ResourceBase] $this).Set()

    # If needed, additional state changes that can not be handled by Modify()
}

hidden [System.Collections.Hashtable] GetCurrentState([System.Collections.Hashtable] $properties)
{
    # Always return current state as hashtable, $properties contains key properties
}

hidden [void] Modify([System.Collections.Hashtable] $properties)
{
    # Always set desired state, $properties contain those that must change state
}

Optional Method Pattern

hidden [void] AssertProperties([System.Collections.Hashtable] $properties)
{
    # Validate user-provided properties, $p...

Files:

  • source/Classes/002.ServerPermission.ps1
  • source/Classes/002.DatabasePermission.ps1
source/**/*.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-localization.instructions.md)

source/**/*.ps1: Localize all Write-Debug, Write-Verbose, Write-Error, Write-Warning and $PSCmdlet.ThrowTerminatingError() messages in PowerShell scripts
Use localized string keys from $script:localizedData, not hardcoded strings, in diagnostic messages
Reference localized strings using the syntax: Write-Verbose -Message ($script:localizedData.KeyName -f $value1)

Localize all strings using string keys; remove any orphaned string keys

Files:

  • source/Classes/002.ServerPermission.ps1
  • source/Classes/002.DatabasePermission.ps1

⚙️ CodeRabbit configuration file

source/**/*.ps1: # Localization Guidelines

Requirements

  • Localize all Write-Debug, Write-Verbose, Write-Error, Write-Warning and $PSCmdlet.ThrowTerminatingError() messages
  • Use localized string keys, not hardcoded strings
  • Assume $script:localizedData is available

String Files

  • Commands/functions: source/en-US/{MyModuleName}.strings.psd1
  • Class resources: source/en-US/{ResourceClassName}.strings.psd1

Key Naming Patterns

  • Format: Verb_FunctionName_Action (underscore separators), e.g. Get_Database_ConnectingToDatabase

String Format

ConvertFrom-StringData @'
    KeyName = Message with {0} placeholder. (PREFIX0001)
'@

String IDs

  • Format: (PREFIX####)
  • PREFIX: First letter of each word in class or function name (SqlSetup → SS, Get-SqlDscDatabase → GSDD)
  • Number: Sequential from 0001

Usage

Write-Verbose -Message ($script:localizedData.KeyName -f $value1)

Files:

  • source/Classes/002.ServerPermission.ps1
  • source/Classes/002.DatabasePermission.ps1
source/Classes/*.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines.instructions.md)

source/Classes/*.ps1: Classes should be located in source/Classes/{DependencyGroupNumber}.{ClassName}.ps1
DSC resources should always be created as class-based resources

Files:

  • source/Classes/002.ServerPermission.ps1
  • source/Classes/002.DatabasePermission.ps1
**/*.{ps1,psm1,psd1}

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-powershell.instructions.md)

**/*.{ps1,psm1,psd1}: Use descriptive names (3+ characters, no abbreviations) for functions, parameters, variables, and classes
Functions: Use PascalCase with Verb-Noun format using approved verbs
Parameters: Use PascalCase naming
Variables: Use camelCase naming
Keywords: Use lower-case
Classes: Use PascalCase naming
Include scope for script/global/environment variables: $script:, $global:, $env:
Use 4 spaces for indentation (no tabs)
Use one space around operators: $a = 1 + 2
Use one space between type and variable: [String] $name
Use one space between keyword and parenthesis: if ($condition)
No spaces on empty lines
Limit lines to 120 characters
Place newline before opening brace (except variable assignments)
Place one newline after opening brace
Place two newlines after closing brace (one if followed by another brace or continuation)
Use single quotes unless variable expansion is needed: 'text' vs "text $variable"
For single-line arrays use: @('one', 'two', 'three')
For multi-line arrays: place each element on separate line with proper indentation
Do not use the unary comma operator (,) in return statements to force an array
For empty hashtables use: @{}
For hashtables: place each property on separate line with proper indentation and use PascalCase for property names
Single-line comments: use # Comment format (capitalized, on own line)
Multi-line comments: use <# Comment #> format (opening and closing brackets on own line with indented text)
No commented-out code
Always add comment-based help to all functions and scripts with SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, and EXAMPLE sections before function/class
Comment-based help indentation: keywords 4 spaces, text 8 spaces
Include examples in comment-based help for all parameter sets and combinations
INPUTS section in comment-based help: List each pipeline-accepted type as inline code with a 1-line description, repeat keyword for each input type, specify None. if there are no inp...

Files:

  • source/Classes/002.ServerPermission.ps1
  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • source/Classes/002.DatabasePermission.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
**/[0-9][0-9][0-9].*.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-powershell.instructions.md)

Class files: Use ###.ClassName.ps1 format (e.g., 001.SqlReason.ps1, 004.StartupParameters.ps1)

Files:

  • source/Classes/002.ServerPermission.ps1
  • source/Classes/002.DatabasePermission.ps1
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

  • Command: Public command
  • Function: Private function
  • Resource: DSC class-based resource

Build & Test Workflow Requirements

  • Run PowerShell script files from repository root
  • Setup build and test environment (once per pwsh session): ./build.ps1 -Tasks noop
  • Build project before running tests: ./build.ps1 -Tasks build
  • Always run tests in new pwsh session: Invoke-Pester -Path @({test paths}) -Output Detailed

File Organization

  • Public commands: source/Public/{CommandName}.ps1
  • Private functions: source/Private/{FunctionName}.ps1
  • Classes: source/Classes/{DependencyGroupNumber}.{ClassName}.ps1
  • Enums: source/Enum/{DependencyGroupNumber}.{EnumName}.ps1
  • Unit tests: tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1
  • Integration tests: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1

Requirements

  • Follow instructions over existing code patterns
  • Follow PowerShell style and test guideline instructions strictly
  • Always update CHANGELOG.md Unreleased section
  • Localize all strings using string keys; remove any orphaned string keys
  • Check DscResource.Common before creating private functions
  • Separate reusable logic into private functions
  • DSC resources should always be created as class-based resources
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • source/Classes/002.ServerPermission.ps1
  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • source/Classes/002.DatabasePermission.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
  • CHANGELOG.md
{**/*.ps1,**/*.psm1,**/*.psd1}

⚙️ CodeRabbit configuration file

{**/*.ps1,**/*.psm1,**/*.psd1}: # PowerShell Guidelines

Naming

  • Use descriptive names (3+ characters, no abbreviations)
  • Functions: PascalCase with Verb-Noun format using approved verbs
  • Parameters: PascalCase
  • Variables: camelCase
  • Keywords: lower-case
  • Classes: PascalCase
  • Include scope for script/global/environment variables: $script:, $global:, $env:

File naming

  • Class files: ###.ClassName.ps1 format (e.g. 001.SqlReason.ps1, 004.StartupParameters.ps1)

Formatting

Indentation & Spacing

  • Use 4 spaces (no tabs)
  • One space around operators: $a = 1 + 2
  • One space between type and variable: [String] $name
  • One space between keyword and parenthesis: if ($condition)
  • No spaces on empty lines
  • Try to limit lines to 120 characters

Braces

  • Newline before opening brace (except variable assignments)
  • One newline after opening brace
  • Two newlines after closing brace (one if followed by another brace or continuation)

Quotes

  • Use single quotes unless variable expansion is needed: 'text' vs "text $variable"

Arrays

  • Single line: @('one', 'two', 'three')
  • Multi-line: each element on separate line with proper indentation
  • Do not use the unary comma operator (,) in return statements to force
    an array

Hashtables

  • Empty: @{}
  • Each property on separate line with proper indentation
  • Properties: Use PascalCase

Comments

  • Single line: # Comment (capitalized, on own line)
  • Multi-line: <# Comment #> format (opening and closing brackets on own line), and indent text
  • No commented-out code

Comment-based help

  • Always add comment-based help to all functions and scripts
  • Comment-based help: SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, EXAMPLE sections before function/class
  • Comment-based help indentation: keywords 4 spaces, text 8 spaces
  • Include examples for all parameter sets and combinations
  • INPUTS: List each pipeline‑accepted type as inline code with a 1‑line description...

Files:

  • source/Classes/002.ServerPermission.ps1
  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • source/Classes/002.DatabasePermission.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
**/*.[Tt]ests.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-pester.instructions.md)

**/*.[Tt]ests.ps1: All public commands, private functions and classes must have unit tests
All public commands and class-based resources must have integration tests
Use Pester v5 syntax only
Test code only inside Describe blocks
Assertions only in It blocks
Never test verbose messages, debug messages or parameter binding behavior
Pass all mandatory parameters to avoid prompts
Inside It blocks, assign unused return objects to $null (unless part of pipeline)
Tested entity must be called from within the It blocks
Keep results and assertions in same It block
Avoid try-catch-finally for cleanup, use AfterAll or AfterEach
Avoid unnecessary remove/recreate cycles
One Describe block per file matching the tested entity name
Context descriptions start with 'When'
It descriptions start with 'Should', must not contain 'when'
Mock variables prefix: 'mock'
Public commands: Never use InModuleScope (unless retrieving localized strings or creating an object using an internal class)
Private functions/class resources: Always use InModuleScope
Each class method = separate Context block
Each scenario = separate Context block
Use nested Context blocks for complex scenarios
Mocking in BeforeAll (BeforeEach only when required)
Setup/teardown in BeforeAll,BeforeEach/AfterAll,AfterEach close to usage
Spacing between blocks, arrange, act, and assert for readability
PascalCase: Describe, Context, It, Should, BeforeAll, BeforeEach, AfterAll, AfterEach
Use -BeTrue/-BeFalse never -Be $true/-Be $false
Never use Assert-MockCalled, use Should -Invoke instead
No Should -Not -Throw - invoke commands directly
Never add an empty -MockWith block
Omit -MockWith when returning $null
Set $PSDefaultParameterValues for Mock:ModuleName, Should:ModuleName, InModuleScope:ModuleName
Omit -ModuleName parameter on Pester commands
Never use Mock inside InModuleScope-block
Never use param() inside -MockWith scriptblock...

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1

⚙️ CodeRabbit configuration file

**/*.[Tt]ests.ps1: # Tests Guidelines

Core Requirements

  • All public commands, private functions and classes must have unit tests
  • All public commands and class-based resources must have integration tests
  • Use Pester v5 syntax only
  • Test code only inside Describe blocks
  • Assertions only in It blocks
  • Never test verbose messages, debug messages or parameter binding behavior
  • Pass all mandatory parameters to avoid prompts

Requirements

  • Inside It blocks, assign unused return objects to $null (unless part of pipeline)
  • Tested entity must be called from within the It blocks
  • Keep results and assertions in same It block
  • Avoid try-catch-finally for cleanup, use AfterAll or AfterEach
  • Avoid unnecessary remove/recreate cycles

Naming

  • One Describe block per file matching the tested entity name
  • Context descriptions start with 'When'
  • It descriptions start with 'Should', must not contain 'when'
  • Mock variables prefix: 'mock'

Structure & Scope

  • Public commands: Never use InModuleScope (unless retrieving localized strings or creating an object using an internal class)
  • Private functions/class resources: Always use InModuleScope
  • Each class method = separate Context block
  • Each scenario = separate Context block
  • Use nested Context blocks for complex scenarios
  • Mocking in BeforeAll (BeforeEach only when required)
  • Setup/teardown in BeforeAll,BeforeEach/AfterAll,AfterEach close to usage
  • Spacing between blocks, arrange, act, and assert for readability

Syntax Rules

  • PascalCase: Describe, Context, It, Should, BeforeAll, BeforeEach, AfterAll, AfterEach
  • Use -BeTrue/-BeFalse never -Be $true/-Be $false
  • Never use Assert-MockCalled, use Should -Invoke instead
  • No Should -Not -Throw - invoke commands directly
  • Never add an empty -MockWith block
  • Omit -MockWith when returning $null
  • Set $PSDefaultParameterValues for Mock:ModuleName, Should:ModuleName, `...

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
tests/Unit/Classes/*.[Tt]ests.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-pester.instructions.md)

Class resources: tests/Unit/Classes/{Name}.Tests.ps1

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
tests/Unit/**/*.Tests.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines.instructions.md)

Unit tests should be located in tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
tests/[Uu]nit/**/*.[Tt]ests.ps1

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-unit-tests.instructions.md)

tests/[Uu]nit/**/*.[Tt]ests.ps1: Test with localized strings using InModuleScope -ScriptBlock { $script:localizedData.Key } in Pester unit tests
Mock files using the $TestDrive variable (path to the test drive) in Pester unit tests
All public commands require parameter set validation tests in unit tests
Use the exact Pester test setup block with BeforeDiscovery, BeforeAll, and AfterAll blocks before Describe in unit tests, including DscResource.Test module import and PSDefaultParameterValues configuration
Use parameter set validation test template with Get-Command and ParameterSets property, supporting both single and multiple parameter sets via -ForEach array in Pester unit tests
Use parameter properties test template with Get-Command to validate individual parameter attributes (e.g., Mandatory flag) in Pester unit tests

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1

⚙️ CodeRabbit configuration file

tests/[Uu]nit/**/*.[Tt]ests.ps1: # Unit Tests Guidelines

  • Test with localized strings: Use InModuleScope -ScriptBlock { $script:localizedData.Key }
  • Mock files: Use $TestDrive variable (path to the test drive)
  • All public commands require parameter set validation tests
  • After modifying classes, always run tests in new session (for changes to take effect)

Test Setup Requirements

Use this exact setup block before Describe:

[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')]
param ()

BeforeDiscovery {
    try
    {
        if (-not (Get-Module -Name 'DscResource.Test'))
        {
            # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task.
            if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
            {
                # Redirect all streams to $null, except the error stream (stream 2)
                & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null
            }

            # If the dependencies have not been resolved, this will throw an error.
            Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
        }
    }
    catch [System.IO.FileNotFoundException]
    {
        throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks noop" first.'
    }
}

BeforeAll {
    $script:moduleName = '{MyModuleName}'

    Import-Module -Name $script:moduleName -ErrorAction 'Stop'

    $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName
    $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName
    $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName
}

AfterAll {
    $PSDefaultParameterValues.Remove('InModuleScope:ModuleName')
    $PSDefaultParameterValues.Remove('Mock:ModuleName')
   ...

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
**/tests/Unit/**/*.ps1

📄 CodeRabbit inference engine (.github/instructions/SqlServerDsc-guidelines.instructions.md)

**/tests/Unit/**/*.ps1: Unit tests must use SMO stub types from SMO.cs, never mock SMO types
Unit tests must add $env:SqlServerDscCI = $true in BeforeAll block and remove in AfterAll block
Load SMO stub types from SMO.cs in unit test files using Add-Type -Path "$PSScriptRoot/../Stubs/SMO.cs"

Files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
CHANGELOG.md

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-changelog.instructions.md)

CHANGELOG.md: Always update the Unreleased section in CHANGELOG.md
Use Keep a Changelog format in CHANGELOG.md
Describe notable changes briefly in CHANGELOG.md, ≤2 items per change type
Reference issues using format issue #<issue_number> in CHANGELOG.md
No empty lines between list items in same section of CHANGELOG.md
Skip adding entry if same change already exists in Unreleased section of CHANGELOG.md
No duplicate sections or items in Unreleased section of CHANGELOG.md

Always update CHANGELOG.md Unreleased section

Files:

  • CHANGELOG.md

⚙️ CodeRabbit configuration file

CHANGELOG.md: # Changelog Guidelines

  • Always update the Unreleased section in CHANGELOG.md
  • Use Keep a Changelog format
  • Describe notable changes briefly, ≤2 items per change type
  • Reference issues using format issue #<issue_number>
  • No empty lines between list items in same section
  • Skip adding entry if same change already exists in Unreleased section
  • No duplicate sections or items in Unreleased section

Files:

  • CHANGELOG.md
**/*.md

📄 CodeRabbit inference engine (.github/instructions/dsc-community-style-guidelines-markdown.instructions.md)

**/*.md: Wrap lines at word boundaries when over 80 characters (except tables/code blocks)
Use 2 spaces for indentation in Markdown files
Use '1.' for all items in ordered lists (1/1/1 numbering style)
Disable MD013 rule by adding a comment for tables/code blocks exceeding 80 characters
Empty lines required before/after code blocks and headings (except before line 1)
Escape backslashes in file paths only (not in code blocks)
Code blocks must specify language identifiers
Format parameters using bold in Markdown documentation
Format values and literals using inline code in Markdown documentation
Format resource/module/product names using italic in Markdown documentation
Format commands/files/paths using inline code in Markdown documentation

Files:

  • CHANGELOG.md

⚙️ CodeRabbit configuration file

**/*.md: # Markdown Style Guidelines

  • Wrap lines at word boundaries when over 80 characters (except tables/code blocks)
  • Use 2 spaces for indentation
  • Use '1.' for all items in ordered lists (1/1/1 numbering style)
  • Disable MD013 rule by adding a comment for tables/code blocks exceeding 80 characters
  • Empty lines required before/after code blocks and headings (except before line 1)
  • Escape backslashes in file paths only (not in code blocks)
  • Code blocks must specify language identifiers

Text Formatting

  • Parameters: bold
  • Values/literals: inline code
  • Resource/module/product names: italic
  • Commands/files/paths: inline code

Files:

  • CHANGELOG.md
🧠 Learnings (27)
📓 Common learnings
Learnt from: johlju
Repo: dsccommunity/SqlServerDsc PR: 2136
File: source/Public/Remove-SqlDscLogin.ps1:104-108
Timestamp: 2025-08-17T10:13:30.079Z
Learning: In SqlServerDsc unit tests, SMO object stubs (like Login objects) should have properly mocked Parent properties with correct Server stub types and valid InstanceName values, rather than handling null Parent scenarios in production code.
📚 Learning: 2026-01-01T11:57:15.286Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/SqlServerDsc-guidelines.instructions.md:0-0
Timestamp: 2026-01-01T11:57:15.286Z
Learning: Applies to **/tests/Unit/**/*.ps1 : Unit tests must add `$env:SqlServerDscCI = $true` in `BeforeAll` block and remove in `AfterAll` block

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to tests/Unit/Public/*.[Tt]ests.ps1 : Public commands: `tests/Unit/Public/{Name}.Tests.ps1`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-08-17T10:13:30.079Z
Learnt from: johlju
Repo: dsccommunity/SqlServerDsc PR: 2136
File: source/Public/Remove-SqlDscLogin.ps1:104-108
Timestamp: 2025-08-17T10:13:30.079Z
Learning: In SqlServerDsc unit tests, SMO object stubs (like Login objects) should have properly mocked Parent properties with correct Server stub types and valid InstanceName values, rather than handling null Parent scenarios in production code.

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to tests/Unit/Private/*.[Tt]ests.ps1 : Private functions: `tests/Unit/Private/{Name}.Tests.ps1`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Each class method = separate `Context` block

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-12-30T15:15:25.261Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-integration-tests.instructions.md:0-0
Timestamp: 2025-12-30T15:15:25.261Z
Learning: Applies to tests/[iI]ntegration/**/*.[iI]ntegration.[tT]ests.ps1 : Integration tests must cover all scenarios and code paths

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Use nested `Context` blocks for complex scenarios

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to tests/Unit/Classes/*.[Tt]ests.ps1 : Class resources: `tests/Unit/Classes/{Name}.Tests.ps1`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Each scenario = separate `Context` block

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : All public commands and class-based resources must have integration tests

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Never use `Mock` inside `InModuleScope`-block

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Set `$PSDefaultParameterValues` for `Mock:ModuleName`, `Should:ModuleName`, `InModuleScope:ModuleName`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-08-17T10:15:48.194Z
Learnt from: johlju
Repo: dsccommunity/SqlServerDsc PR: 2136
File: tests/Unit/Public/Remove-SqlDscLogin.Tests.ps1:36-39
Timestamp: 2025-08-17T10:15:48.194Z
Learning: Public command unit tests guideline: Never use InModuleScope unless accessing localized strings from $script:localizedData. PSDefaultParameterValues for InModuleScope should be kept in public command tests to support localized string retrieval when necessary.

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Mock variables prefix: 'mock'

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Private functions/class resources: Always use `InModuleScope`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Public commands: Never use `InModuleScope` (unless retrieving localized strings or creating an object using an internal class)

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2026-01-01T11:57:15.286Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/SqlServerDsc-guidelines.instructions.md:0-0
Timestamp: 2026-01-01T11:57:15.286Z
Learning: Applies to **/tests/Integration/**/*.ps1 : Integration tests must use `Disconnect-SqlDscDatabaseEngine` after `Connect-SqlDscDatabaseEngine`

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T18:00:35.078Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines.instructions.md:0-0
Timestamp: 2025-11-27T18:00:35.078Z
Learning: Follow PowerShell style and test guideline instructions strictly

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2026-01-01T11:57:15.286Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/SqlServerDsc-guidelines.instructions.md:0-0
Timestamp: 2026-01-01T11:57:15.286Z
Learning: Applies to **/tests/Unit/**/*.ps1 : Unit tests must use SMO stub types from SMO.cs, never mock SMO types

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Never use `Assert-MockCalled`, use `Should -Invoke` instead

Applied to files:

  • tests/Unit/Classes/ServerPermission.Tests.ps1
  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-12-30T15:15:36.079Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-unit-tests.instructions.md:0-0
Timestamp: 2025-12-30T15:15:36.079Z
Learning: Applies to tests/[Uu]nit/**/*.[Tt]ests.ps1 : Use the exact Pester test setup block with `BeforeDiscovery`, `BeforeAll`, and `AfterAll` blocks before `Describe` in unit tests, including `DscResource.Test` module import and PSDefaultParameterValues configuration

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : One `Describe` block per file matching the tested entity name

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Omit `-MockWith` when returning `$null`

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-09-25T16:38:08.867Z
Learnt from: johlju
Repo: dsccommunity/ActiveDirectoryDsc PR: 741
File: tests/Integration/MSFT_ADReadOnlyDomainControllerAccount.Integration.Tests.ps1:102-104
Timestamp: 2025-09-25T16:38:08.867Z
Learning: The PowerShell guideline "Use -BeTrue/-BeFalse; never use -Be $true/-Be $false" applies only when the actual return value is a boolean. When a cmdlet returns string values like 'True' or 'False', Should -Be 'True' is the appropriate assertion.

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Mocking in `BeforeAll` (`BeforeEach` only when required)

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
📚 Learning: 2025-11-27T17:59:27.205Z
Learnt from: CR
Repo: dsccommunity/SqlServerDsc PR: 0
File: .github/instructions/dsc-community-style-guidelines-pester.instructions.md:0-0
Timestamp: 2025-11-27T17:59:27.205Z
Learning: Applies to **/*.[Tt]ests.ps1 : Use `-BeTrue`/`-BeFalse` never `-Be $true`/`-Be $false`

Applied to files:

  • tests/Unit/Classes/DatabasePermission.Tests.ps1
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: PSScriptAnalyzer
  • GitHub Check: dsccommunity.SqlServerDsc (Build Package Module)
🔇 Additional comments (10)
source/Classes/002.DatabasePermission.ps1 (1)

186-186: LGTM! Critical equality bug fixed.

The fix correctly compares State instead of the non-existent Grant property, ensuring equality checks work as intended.

source/Classes/002.ServerPermission.ps1 (1)

118-118: LGTM! Critical equality bug fixed.

The fix correctly compares State instead of the non-existent Grant property, mirroring the fix in DatabasePermission.

tests/Unit/Classes/DatabasePermission.Tests.ps1 (2)

133-191: LGTM! Test reorganization follows Pester guidelines.

The nested contexts properly separate scenarios (Deny vs Grant, Grant vs GrantWithGrant) and each test clearly validates that objects with different State values are not equal.


225-279: LGTM! Comprehensive GetHashCode() test coverage.

The tests thoroughly validate GetHashCode() behavior:

  • Equal objects produce identical hash codes (including order-independent Permission arrays)
  • Different State produces different hash codes
  • Different Permission produces different hash codes

The implementation correctly uses nested contexts and InModuleScope following Pester guidelines.

tests/Unit/Classes/ServerPermission.Tests.ps1 (6)

74-79: LGTM!

Variable renaming from $databasePermissionInstance to $serverPermissionInstance correctly reflects the class under test.


96-127: LGTM!

Consistent variable renaming in equality tests for both single and multiple permission scenarios.


133-191: Well-structured tests for the core bug fix.

These new test contexts properly validate that Equals() now correctly compares the State property, ensuring instances with Deny vs Grant and Grant vs GrantWithGrant are not considered equal.


199-220: LGTM!

Variable renaming applied consistently in the Permission comparison tests.


225-279: Comprehensive GetHashCode() coverage.

The tests correctly verify:

  1. Equal objects produce identical hash codes (including permission order independence via sorted normalization at lines 233/237)
  2. Different State values produce different hash codes
  3. Different Permission values produce different hash codes

Note: While hash collisions are technically permitted by the GetHashCode() contract, testing for inequality on clearly different inputs is reasonable for validating a well-implemented hash function.


31-51: Test setup follows all required conventions.

Proper configuration of $env:SqlServerDscCI, module import without -Force (preserving type identity for class comparisons), and correct PSDefaultParameterValues setup per coding guidelines.

@codecov
Copy link

codecov bot commented Jan 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94%. Comparing base (4904751) to head (bffc1ab).

Additional details and impacted files

Impacted file tree graph

@@          Coverage Diff          @@
##            main   #2392   +/-   ##
=====================================
  Coverage     94%     94%           
=====================================
  Files        186     186           
  Lines      10238   10248   +10     
=====================================
+ Hits        9633    9643   +10     
  Misses       605     605           
Flag Coverage Δ
unit 94% <100%> (+<1%) ⬆️
Files with missing lines Coverage Δ
source/Classes/002.DatabasePermission.ps1 100% <100%> (ø)
source/Classes/002.ServerPermission.ps1 100% <100%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Removed TODO comment from ServerPermission.GetHashCode() as requested
- Simplified GetHashCode() initialization in both classes to directly assign State hash code
- Changed from initializing to 0 then assigning to direct assignment
- All 64 unit tests pass

Co-authored-by: johlju <[email protected]>
Copilot AI requested a review from johlju January 4, 2026 15:40
@johlju
Copy link
Member

johlju commented Jan 4, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@johlju johlju merged commit 79e3a0c into main Jan 4, 2026
4 of 9 checks passed
@johlju johlju deleted the copilot/fix-databasepermission-equals-bug branch January 4, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DatabasePermission.Equals() only compares Permission property, ignores State property

2 participants