Complete AL review knowledge readiness (#108)
Some checks failed
Validate knowledge index / validate-index (push) Has been cancelled
Validate AL review fixtures / validate-review-fixtures (push) Has been cancelled
Validate frontmatter and structure / validate (push) Has been cancelled

* Complete AL review knowledge readiness

Fill telemetry and Query coverage, strengthen thin review domains, correct audited content defects, and add deterministic cheap-model evaluation and reference-integrity safeguards.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

* Generalize review fixture discovery

Derive smoke cases from the leaf, domain, and paired-sample conventions so new leaves require no scoring-contract changes. Keep only exceptional selection/context overrides and fail when retrieval metadata cannot rank the selected article.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

* Preserve published field IDs in sample

Keep the existing Email and Contact Email field IDs unchanged, clarify that the sample represents an independent baseline, and use a local breaking-change rule for the generic smoke evaluation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

* Clarify published field identity rules

State explicitly that a published field keeps its ID, name, and type while a replacement is added as a separate field under an unused ID.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

* Align field obsoletion sample baselines

Use Email field ID 3 as the shared baseline so the bad example demonstrates a same-ID rename while the good example retains the original field and adds a separate replacement.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27

---------

Co-authored-by: Jesper Schulz-Wedde <jesper.schulzwedde@microsoft.com>
This commit is contained in:
Jesper Schulz-Wedde 2026-07-15 10:55:25 +02:00 committed by GitHub
parent ae04938c03
commit 186d8a1314
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
105 changed files with 2229 additions and 212 deletions

View file

@ -0,0 +1,26 @@
codeunit 50483 "Protected Setup Action Bad"
{
trigger OnRun()
var
Customer: Record Customer;
begin
Customer.Init();
Customer."No." := 'SUPER-INSERT';
Customer.Insert();
end;
}
codeunit 50484 "Permission Test Bad"
{
Subtype = Test;
TestPermissions = Disabled;
[Test]
procedure LimitedUserCannotRunSetup()
var
SetupAction: Codeunit "Protected Setup Action Bad";
begin
// Disabled runs as SUPER; no limited-user boundary is exercised.
asserterror SetupAction.Run();
end;
}

View file

@ -0,0 +1,43 @@
permissionset 50480 "LIMITED USER"
{
Assignable = false;
Permissions =
tabledata Customer = R,
codeunit "Protected Setup Action Test" = X;
}
codeunit 50481 "Protected Setup Action Test"
{
trigger OnRun()
var
Customer: Record Customer;
begin
Customer.Init();
Customer."No." := 'NO-INSERT';
Customer.Insert();
end;
}
codeunit 50482 "Permission Test Good"
{
Subtype = Test;
TestPermissions = Restrictive;
[Test]
procedure LimitedUserCannotRunSetup()
var
PermissionsMock: Codeunit "Permissions Mock";
SetupAction: Codeunit "Protected Setup Action Test";
begin
PermissionsMock.Start();
PermissionsMock.SetExactPermissionSet('LIMITED USER');
asserterror SetupAction.Run();
Assert.ExpectedError('permission');
PermissionsMock.Stop();
end;
var
Assert: Codeunit "Library Assert";
}

View file

@ -0,0 +1,26 @@
---
bc-version: [all]
domain: testing
keywords: [testpermissions, restrictive, disabled, permissions-mock, lower-permissions, super, permission-test]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Permission tests must actually lower the execution context
## Description
`TestPermissions` describes how a test runner should establish the permission context; the enum value does not itself assign the business permission set being tested. `Restrictive` is the default and starts from D365 Full Access, requiring the test to lower permissions. `Disabled` leaves the test running as `SUPER`. A test that expects access to be denied while still running with either broad context can pass or fail for the wrong reason and never exercise the intended boundary.
## Best Practice
Use `TestPermissions::Restrictive` for a permission-sensitive test and lower the current test user with the test framework's `"Permissions Mock"` or `"Library - Lower Permissions"` before invoking the protected operation. Assign the exact permission set the scenario claims to test and restore or stop the mock afterward. Use `Disabled` only for suites that do not assert permission behavior.
See sample: `permission-tests-must-lower-the-execution-context.good.al`.
## Anti Pattern
Setting `TestPermissions = Disabled` or leaving the effective D365 Full Access context in place while asserting that a limited user is denied, or adding a `[TestPermissions(...)]` attribute without any runner/test-library code that applies the intended permission set.
See sample: `permission-tests-must-lower-the-execution-context.bad.al`.

View file

@ -0,0 +1,22 @@
codeunit 50452 "Isolated Test Runner Bad"
{
Subtype = TestRunner;
TestIsolation = Disabled;
}
codeunit 50453 "Committed Write Test Bad"
{
Subtype = Test;
[Test]
[TransactionModel(TransactionModel::AutoCommit)]
procedure TestCommittedWrite()
var
Customer: Record Customer;
begin
Customer.Init();
Customer."No." := 'PERSISTS';
Customer.Insert();
Commit();
end;
}

View file

@ -0,0 +1,22 @@
codeunit 50450 "Isolated Test Runner Good"
{
Subtype = TestRunner;
TestIsolation = Codeunit;
}
codeunit 50451 "Committed Write Test Good"
{
Subtype = Test;
[Test]
[TransactionModel(TransactionModel::AutoCommit)]
procedure TestCommittedWrite()
var
Customer: Record Customer;
begin
Customer.Init();
Customer."No." := 'ISOLATED';
Customer.Insert();
Commit();
end;
}

View file

@ -0,0 +1,26 @@
---
bc-version: [all]
domain: testing
keywords: [testisolation, testrunner, autocommit, commit, rollback, test-order, database-state]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Configure TestIsolation on the test runner
## Description
`TestIsolation` is a property of a `Subtype = TestRunner` codeunit, not of the test codeunit being executed. Its default is `Disabled`. `Codeunit` rolls back database changes after each test codeunit and `Function` after each test method, including changes that the code under test explicitly committed. Without runner isolation, an `AutoCommit` test can leave data behind and make later tests order-dependent.
## Best Practice
Run independent suites with `TestIsolation = Codeunit` or `Function`, choosing the narrowest boundary the runner supports. Pair this with the appropriate method-level `TransactionModel`: `AutoCommit` permits code under test to commit, while runner isolation still restores the database afterward. Keep isolation disabled only for an intentionally shared-state suite whose ordering and cleanup are explicit.
See sample: `testisolation-belongs-on-the-test-runner.good.al`.
## Anti Pattern
An `AutoCommit` test exercises committed writes under a test runner that omits `TestIsolation` or sets it to `Disabled`, then assumes the database is restored automatically. This article owns runner-level rollback; `transactionmodel-attribute-governs-test-transactions.md` separately owns the method attribute.
See sample: `testisolation-belongs-on-the-test-runner.bad.al`.