UnitAutogen.psd1

@{
    ModuleVersion     = '0.16.8'
    GUID              = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
    Author            = 'Munaf Ibrahim Khatri'
    CompanyName       = 'UnitAutogen'
    Copyright         = '(C) 2026 Munaf Ibrahim Khatri. Licensed under AGPL-3.0.'
    Description       = 'PowerShell module for UnitAutogen - auto-generated tSQLt unit tests with real branch coverage for SQL Server. Installs the framework AND the in-database (SQLCLR) predicate parser, runs generation and coverage, and exports Cobertura XML, JUnit XML, and HTML reports for Azure DevOps, GitHub Actions, Jenkins, GitLab CI, and SonarQube. The single C# predicate parser runs inside SQL Server (no PowerShell-side parser); installation registers it and requires sysadmin once plus ''clr enabled''=1.'
    PowerShellVersion = '5.1'
    RootModule        = 'UnitAutogen.psm1'

    FunctionsToExport = @(
        'Install-UnitAutogenDatabase',
        'Invoke-UnitAutogen',
        'Export-CoverageCoberturaXml',
        'Export-TestResultsJunitXml',
        'Export-CoverageHtmlReport',
        'Export-UnitAutogenTests'
    )

    CmdletsToExport   = @()
    VariablesToExport = @()
    AliasesToExport   = @()

    # All files that must be present for the module to work
    FileList = @(
        'UnitAutogen.psd1',
        'UnitAutogen.psm1',
        'sql\Install_UnitAutogen.sql',
        'sql\Install-UnitAutogenClr.SSMS.sql'
    )

    PrivateData = @{
        PSData = @{
            ExternalModuleDependencies = @('SqlServer')
            Tags        = @('SQL', 'SQLServer', 'tSQLt', 'Coverage', 'CI-CD',
                            'Cobertura', 'JUnit', 'AzureDevOps', 'Testing',
                            'UnitTest', 'CodeCoverage', 'BranchCoverage',
                            'DatabaseTesting', 'AutomatedTesting')
            LicenseUri  = 'https://github.com/unitautogen/unitautogen-public-repo/blob/main/LICENSE'
            ProjectUri  = 'https://github.com/unitautogen/unitautogen-public-repo'
            IconUri     = 'https://raw.githubusercontent.com/unitautogen/unitautogen-public-repo/main/docs/logo.png'
            ReleaseNotes = @'
## v0.16.8 (beta) - 2026-06-18
 
- **Parenthesised sub-expressions in per-row arithmetic gates are now seeded.** A branch whose value
  groups an additive sub-expression in parentheses - e.g. `value = (qty + fee) * rate` or
  `value = qty * (price - fee)` - was previously left NOT_TESTABLE. A lightweight paren-depth tracker now
  splits the expression into top-level factors and neutralises each non-driving column correctly (0 for an
  additive sibling, 1 for a multiplicative one), so both arms are covered. Pure-product parens and
  paren-free expressions are unchanged.
- Fail-safe by design: a top-level sum mixing paren groups, nested parens, a constant inside a paren, or any
  unresolved column still falls back to an honest NOT_TESTABLE - never a wrong witness.
- Validated on a synthetic per-row procedure (correct co-factors; coverage identical to the non-paren
  equivalent) with full PredicateZoo + reference-DB regression unchanged. Pure T-SQL; no CLR change.
 
## v0.16.7 (beta) - 2026-06-18
 
- **Nondeterministic-gate guard (no more runaway searches).** A branch whose operand is built from a
  runtime value the seeder cannot control - a clock (SYSDATETIME / GETDATE / CURRENT_TIMESTAMP / ...),
  NEWID, or RAND - is now detected up front and reported as an honest NOT_TESTABLE, instead of the
  search-seeding sweep grinding (in one pathological loop-accumulator fixture, 37+ minutes of CPU)
  before giving up. The detector scans the operand's own assignment lineage; @@ROWCOUNT-style globals
  are deliberately NOT treated as nondeterministic (they reflect seedable row state).
- **Search backstops.** A per-gate wall-clock budget (default 90s) abandons any non-converging search,
  and the loop-count row-count knob is capped at @MaxSeedRows (default 500) so a large comparand can't
  request 100k+ seeded rows per probe. Raise @MaxSeedRows to test a gate that genuinely needs more.
- Pure T-SQL; no CLR change. Validated on AdventureWorks2025 (the fixture now resolves in ~10s; pz
  loop/count/aggregate/scalar/OR gates unchanged) and HighValueCustomer (AssessCustomer 6/6, Reconcile
  15/16 with all witnesses intact) - all 0 fail / 0 err.
 
## v0.16.6 (beta) - 2026-06-17
 
- **IN / BETWEEN in a WHERE are now seeded** (in-database parser enhancement). A branch gated on
  EXISTS/COUNT over "... WHERE col IN (v1, v2, ...)" was previously NOT_TESTABLE; the parser now
  expands it to an OR of equalities, so coverage generates one TRUE test PER value (each seeding a row
  matching only that value). "col BETWEEN a AND b" expands to col >= a AND col <= b and is seeded.
  Requires the updated in-database CLR parser (re-run installer step 2).
- Validated on AdventureWorks2025 (IN gate -> per-value tests with distinct seeds; BETWEEN seeded);
  PredicateZoo regression unchanged.
 
## v0.16.5 (beta) - 2026-06-17
 
- **OR per-arm coverage.** A branch gated on a multi-condition OR over a table (e.g.
  EXISTS(... WHERE a = 1 OR b = 2 OR c = 3)) now generates one TRUE test PER disjunct - each seeding a
  row that satisfies only that arm - instead of a single TRUE test for the first arm, so every OR arm
  is exercised independently. (Branch coverage is unchanged; this adds condition-level thoroughness.)
- A column IN (...) / BETWEEN in a WHERE, and COUNT(col) NULL semantics, remain dependent on a future
  in-database parser enhancement.
- Validated on AdventureWorks2025 (synthetic OR gate: per-arm seeds verified distinct); PredicateZoo
  regression unchanged. No C#/CLR change.
 
## v0.16.4 (beta) - 2026-06-17
 
- **Temp-table tracing.** A branch gated on a #temp populated by SELECT ... INTO #t FROM <base>
  (e.g. a loop bounded by the temp's row count) is now covered: the seeder traces the #temp back to
  its base table and seeds that, since the procedure itself fills the #temp at run time. These gates
  were previously skipped ("target table not found").
- **Parenthesised derived locals - correctness guard.** A per-row arithmetic gate whose value groups
  an additive sub-expression in parentheses (e.g. value = qty * (price - fee)) is now left as an
  honest NOT_TESTABLE instead of being mis-flattened into a wrong witness. (Full distribution is
  future work; pure-product parens and paren-free expressions are unaffected.)
- Validated on AdventureWorks2025 synthetics; PredicateZoo regression unchanged. No C#/CLR change.
 
## v0.16.2 (beta) - 2026-06-17
 
Seeder-robustness batch (1 of 2 from an external code review). The deeper test-generator
and parser items follow in v0.16.3.
 
- A new per-run **@MaxSeedRows** parameter on GenerateAndRunCoverage / GenerateAndCoverDatabase
  makes the seed-row cap tunable (was hardcoded 500); a COUNT(*) gate needing more rows can now
  be covered by raising it. Default 500 - existing behaviour unchanged.
- **Date and string range predicates are now seeded.** A comparand using >, >=, <, <= on a
  date/datetime or string (reporting windows, alphabetical filters) was previously a silent skip;
  the seeder now produces a satisfying value (DATEADD past a date bound; a collation-safe boundary
  for strings). The aggregate-filter seeder reuses the same logic, so "... WHERE d <= '<date>'"
  no longer excludes the seeded row.
- A branch gated on a **single-column contradiction** (e.g. x > y AND x < y) is now reported as
  PROVABLY UNREACHABLE (dead code) instead of a generic skip, via a new constraint classifier.
- Validated on AdventureWorks2025 (configurable-cap and dead-branch synthetics; PredicateZoo
  count/scalar/sum gates unchanged at 100%). No C#/CLR change.
 
## v0.16.1 (beta) - 2026-06-15
 
Two narrower derived-value and aggregate shapes are now seeded to full branch coverage.
 
- A derived local that uses SUBTRACTION (e.g. value = qty * price - fee, or qty * price
  - 100) is now covered. A subtracted column is neutralised to 0 like any other term; a
  subtracted (or added) numeric constant is folded into the knob so the driving term
  still crosses the threshold exactly.
- An aggregate gate whose source has a NON-equality filter is now satisfied: numeric
  >, >=, <, <= seed a value just inside the bound; IN (...) seeds the first list value;
  BETWEEN seeds the low bound. (Equality and date ">=" windows were already handled.)
- Validated on a synthetic loop procedure (100% line + branch); full regression on
  AdventureWorks2025 (PredicateZoo aggregate/scalar gates), a JSON/MERGE/transaction
  procedure, and a multi-procedure analytics DB all unchanged. No C#/CLR change.
 
## v0.16.0 (beta) - 2026-06-15
 
Two more derived-value and aggregate shapes are now seeded to full branch coverage.
 
- A derived local that MIXES multiplication and addition (e.g. value = qty * price +
  fee) is now covered. The generator splits the expression into additive terms, drives
  the term holding the chosen column and neutralises the rest, so the computed value
  crosses the threshold exactly. Pure-product and pure-sum cases are unchanged.
- An aggregate gate whose source has a NON-date filter (e.g. AVG(Score) FROM Metrics
  WHERE Status='ACTIVE') now seeds a row that PASSES the filter instead of a placeholder
  the filter excluded (which left the aggregate NULL and the branch uncovered). This also
  fixes compound gates that reuse such an aggregate to set a flag.
- Validated on a synthetic loop procedure (100% line + branch); full regression on
  AdventureWorks2025 (PredicateZoo aggregate/scalar gates), a JSON/MERGE/transaction
  procedure, and a multi-procedure analytics DB all unchanged. No C#/CLR change.
 
## Earlier releases
 
Full release history (v0.15.x back to v0.9.0) is in CHANGES.md and on the GitHub
Releases page: https://github.com/unitautogen/unitautogen-public-repo/releases
 
'@

        }
    }
}