Skip to content

Next Release (End May)#38

Draft
PepperPix wants to merge 90 commits into
mainfrom
beta
Draft

Next Release (End May)#38
PepperPix wants to merge 90 commits into
mainfrom
beta

Conversation

@PepperPix
Copy link
Copy Markdown
Contributor

No description provided.

PepperPix and others added 30 commits May 22, 2026 10:40
…bool

FetchXml conditions on attributes whose type cannot be resolved via

early-bound model assemblies leaked through GetConditionExpressionValueCast

as strings ("true"/"false"). The left-hand side was cast to bool while

the right-hand side stayed a string, so equality always evaluated to false.

Add a bool.TryParse fallback alongside the existing Guid/numeric/DateTime

fallbacks so bool conditions match correctly without registered metadata.

Co-authored-by: Junie <junie@jetbrains.com>
Co-authored-by: Junie <junie@jetbrains.com>
Co-authored-by: Junie <junie@jetbrains.com>
Co-authored-by: Junie <junie@jetbrains.com>
Co-authored-by: Junie <junie@jetbrains.com>
Co-authored-by: Junie <junie@jetbrains.com>
following qodana
# [1.1.0-beta.1](v1.0.0...v1.1.0-beta.1) (2026-05-22)

### Bug Fixes

* **query:** treat fetchxml bool condition values without metadata as bool ([fe18d0c](fe18d0c))

### Features

* add FetchXmlToQueryExpression organization request fake ([de7cd6f](de7cd6f))
* add QueryExpressionToFetchXml organization request fake ([a18c9b3](a18c9b3))
* add RetrieveAllEntities organization request fake ([f826094](f826094))
…ultiple

RetrieveMultiple did not find entities when filtering by the primary key
attribute (e.g. systemuserid == <guid>), because the filter pipeline only
inspects the Attributes collection while stored entities typically have
the primary id only in Entity.Id.

CreateQuery<T> now ensures the primary id attribute is present on cloned
entities, using EntityMetadata.PrimaryIdAttribute when available or the
<entity>id convention as fallback.

Co-authored-by: Junie <junie@jetbrains.com>
# [1.1.0-beta.2](v1.1.0-beta.1...v1.1.0-beta.2) (2026-05-22)

### Bug Fixes

* **query:** match primary id attribute against Entity.Id in RetrieveMultiple ([a66b55f](a66b55f))
…on in PatchDateFormat

The LINQ .Where() enumeration over record.Attributes was deferred,
causing a 'Collection was modified' exception when the loop body
modified the same Attributes dictionary. Adding .ToList() materializes
the filtered results before iteration begins.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When EntityMetadata is registered with only a LogicalName but no
AttributeMetadata array, the Attributes property is null. Accessing
.SingleOrDefault() on null throws ArgumentNullException. Added an
early return when Attributes is null.

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

When a left outer join produces no matching record, DefaultIfEmpty()
yields null. JoinAttributes now returns the original entity unchanged
when otherEntity is null, matching Dataverse behavior where unmatched
outer joins simply omit the linked attributes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover three scenarios that lock in expected LeftOuter join semantics:
- Outer entity is returned even when no matching inner entity exists
- Multiple matching inner entities produce multiple result rows
- LeftOuter returns more rows than the equivalent Inner join

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# [1.1.0-beta.3](v1.1.0-beta.2...v1.1.0-beta.3) (2026-05-22)

### Bug Fixes

* **query:** guard against null Attributes array in PatchDateFormat ([fdefc11](fdefc11))
* **query:** handle null otherEntity in JoinAttributes for left outer joins ([1a58675](1a58675))
* **query:** materialize DateTime attributes before modifying collection in PatchDateFormat ([9b9aa2d](9b9aa2d))
Replace FastCloner.DeepClone with manual construction of a plain Entity
instance so that the runtime type is always Entity (true upcast).
Attributes, FormattedValues, KeyAttributes and RelatedEntities are
deep-copied via the existing CloneAttribute helper.

Add ToProxyType conversion in RetrieveMultipleFake so that typed LINQ
queries (DataContext) still receive the correct proxy type at query time.

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

The Activator.CreateInstance(entity.GetType()) call is unnecessary now
that the internal store only holds base Entity instances. Use a simple
new Entity(...) constructor consistent with the ColumnSet overload.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move proxy type conversion from per-call reflection (GetMethod +
MakeGenericMethod + Invoke) to pre-built cached delegates in
EntityTypeResolver.ConvertToProxyType. This eliminates repeated
reflection overhead in RetrieveMultipleFake.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace per-call GetCustomAttribute reflection with a static dictionary
cache keyed by Type. The attribute is resolved once per entity type and
reused for all subsequent CreateQuery<T>() calls.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace GetType() + typeof chain with switch pattern matching.
Eliminates per-comparison GetType() call and sequential type equality
checks, letting the JIT use a jump table instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove static EntityLogicalNameCache to avoid shared state across tests.
Instead, use EntityTypeResolver.GetLogicalName() backed by an instance-
scoped reverse type cache (Type → logicalName). All caches are now owned
by the FakeOrganizationService instance — no cross-test side effects.

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

Replace ~20 per-query GetMethod reflection calls with static readonly
MethodInfo fields resolved once at class initialization. Covers string
operations, DateTime.Date, HashSet methods, SDK property getters
(EntityReference.Id/Name, Money.Value, OptionSetValue.Value, etc.),
and the dynamic Like operator (Contains/StartsWith/EndsWith).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In the LeftOuter join path GroupJoin + SelectMany called
x.outerEl.JoinAttributes(...) without cloning first.  When an outer
entity matched multiple inner entities every SelectMany iteration
mutated the same instance, so all result rows ended up sharing the
last inner entity's aliased values.

Add CloneEntity() before JoinAttributes() to mirror the Inner-join
case and ensure each result row is independent.

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

Assert that the two corpB result rows are distinct object instances
(not the same mutated reference) and that each row carries the aliased
first name of its specific contact (John B / John C).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
BuildProxyConverterCache used a lambda that closed over a MethodInfo
and called Invoke on every conversion, keeping full reflection overhead
despite the caching.

Replace with Expression.Lambda<Func<Entity,Entity>>.Compile() so each
cached delegate is emitted as real IL and ConvertToProxyType is truly
reflection-free per call.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CloneAttribute for OptionSetValueCollection used ToArray() which shared
the original OptionSetValue references. Since OptionSetValue.Value has a
setter, mutations to a cloned entity could silently affect the original.

Replace ToArray() with a Select(v => new OptionSetValue(v.Value)) so
each element is its own copy.

Also rename CloneEntity_Should_ReturnEntityRuntimeType_WhenSourceIsDerived
to CloneEntity_Should_ReturnBaseEntityType_EvenWhenSourceIsDerived — the
old name implied the derived type is preserved, but the intended (and
asserted) behaviour is the opposite.

Add CloneEntity_OptionSetValueCollection_Should_BeIndependent to lock in
clone immutability for OptionSetValueCollection attributes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ype is not in resolver cache

TypeResolver.GetLogicalName only finds types discovered via
ProxyTypesAssembly scanning. If the assembly was not registered,
GetLogicalName returned null and the exception claimed the attribute
was missing, which was misleading.

Now fall back to reading EntityLogicalNameAttribute directly from
typeof(T) before throwing, so CreateQuery<T> works for any properly
annotated proxy type regardless of assembly registration. The error
message now also explains the two registration paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PepperPix and others added 25 commits May 26, 2026 08:12
- Add Natural, MatchFirstRowUsingCrossApply to supported joins list
- Document CompareColumns support
- Fix test file comments (remove 'NOT YET IMPLEMENTED', clarify column projection)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- OrderQuery missing ContainsKey on ThenByDescending (throws KeyNotFoundException)
- LastXDays mutates input ConditionExpression.Values array (query reuse broken)
- CompareColumnsHelper MethodInfo reflected every call (not cached)
- MatchFirstRowUsingCrossApply .First() non-deterministic (results vary by insertion order)

Tests 1-3 pass as expected (bugs are proven).
Test 4 fails by design - non-determinism is the bug being demonstrated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1. OrderQuery: Add missing ContainsKey guard on ThenByDescending
   - Was throwing KeyNotFoundException when descending order attribute missing on some entities
   - Now treats missing attributes as null like ThenBy does

2. Values mutation: Stop mutating input ConditionExpression in Last/Next/BetweenDates
   - Last/Next/BetweenDates were calling c.Values.Clear() + Add() on input condition
   - Now creates temporary ConditionExpression with calculated dates instead
   - Enables query reuse pattern (same query can execute multiple times)

3. CompareColumnsHelper: Cache MethodInfo as static readonly field
   - Was using reflection via typeof(...).GetMethod() on every call
   - Now uses s_compareColumnsHelper static field initialized once at class load time
   - Matches pattern of other operator MethodInfo fields

4. MatchFirstRowUsingCrossApply: Add OrderBy before .First() for determinism
   - GroupJoin has no guaranteed ordering, .First() was non-deterministic
   - Results varied based on entity insertion order
   - Now orders by Entity.Id before .First() for stable, deterministic results

Tests updated to verify fixes:
- OrderQuery test now expects success instead of KeyNotFoundException
- LastXDays test verifies Values array is NOT mutated (query reusable)
- CompareColumns test confirms performance improvement
- CrossApply test verifies deterministic behavior regardless of insertion order

All 398 tests pass (0 failures).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move IsOuter early return to top of TranslateConditionExpression
- Make GetEntityNameFromAlias search nested LinkEntities recursively
- Change _operatorsNotToConvertArray to static HashSet for O(1) lookup
- Use ToLowerInvariant() instead of ToLower() in KeySelector
- Make linked entity attribute name prefixing idempotent (strip-then-prefix)
- Create ConditionExpression copy for lookup name fix (no mutation)
- Remove dead ToDayOfWeek/ToDayOfDeltaWeek methods and their test

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add test files for 8 previously untested request fakes:
- DeleteFakeTests (5 tests)
- UpdateFakeTests (7 tests)
- AssignRequestFakeTests (6 tests)
- SetStateFakeTests (4 tests)
- AssociateFakeTests (6 tests)
- DisassociateFakeTests (5 tests)
- ExecuteTransactionFakeTests (6 tests)
- RetrieveEntityFakeTests (5 tests)

Total: 44 new tests, all passing (445 total)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add comprehensive test coverage for:
- ConditionParser (22 tests): equality, comparison, string, collection,
  null, EntityReference, OptionSetValue operators
- ExpressionProcessor (8 tests): And/Or, nested filters, empty filters,
  linked entity alias idempotency
- FetchProcessor (11 tests): operator mapping, link entities, ordering,
  value conversion, In operator
- QueryProcessor (14 tests): TopCount, paging, distinct, ordering,
  column projection, empty results
- LinkedEntitiesProcessor (13 tests): all JoinOperator types, nested
  joins, auto-alias, cross-apply, All/NotAll semantics

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

Phase 3 test coverage:
- DeepCloneExtensions (6 tests): clone preservation, independence,
  null handling, EntityReference, OptionSetValue, nested objects
- ErrorFactory (4 tests): ThrowFault with/without ErrorCodes,
  message propagation, detail verification
- Validators (10 tests): alias/entity matching, duplicate detection,
  unknown entity, recursive nested validation, null/empty cases

Also fix ValidatorsTests assertion style (use Contains instead of
exact match for exception messages).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove InternalsVisibleTo attribute from the main project. The only test
that directly accessed internal types (DeepCloneExtensionsTests) is deleted
because the deep-clone behavior is already covered implicitly through the
public API tests that add and retrieve entities.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update all TUnit test assertions from HasCount().EqualTo() to Count().IsEqualTo()
- Resolves 87 CS0618 obsolete method warnings from Qodana
- Aligns with TUnit v1 assertion API changes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove unused using statements identified by Qodana
- Improves code cleanliness across 11 test files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Clean up unused variables in ConditionParser and CreateFakeDeepInsertTests
- Resolves Qodana warnings

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Convert kvp.Key/kvp.Value patterns to tuple deconstruction
- Applied to RetrieveFake and DeepInsertProcessor
- Improves readability and conciseness

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Simplify BindingFlags usage - fully qualified via using statement
- Improves code readability

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace Entities.Count() with .Count property access
- More efficient and matches framework conventions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace explicit int type with var in for loops
- Improves code readability

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Specify AddMetadata(EntityMetadata) overload in documentation
- Fixes InvalidXmlDocComment warning

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

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The SourceGenerator requires [FastClonerClonable] on types to generate
FastDeepClone() extension methods at compile time. The only clone use
case in this project is QueryExpression (external Dataverse SDK type),
which cannot be annotated. The package was therefore never active.

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

ProcessOneToMany now checks that metadata.ReferencedEntity matches the
parentLogicalName. ProcessManyToMany validates that the parent is either
Entity1 or Entity2 of the relationship. Both throw an InvalidArgument
fault on mismatch instead of silently setting incorrect foreign keys.

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

Only persist recurrencepattern when non-null/empty and recurrencestarttime
when non-default, mirroring Dataverse behavior where unset attributes are
absent rather than holding sentinel values.

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

The test previously asserted ElapsedMilliseconds > 0 which is unreliable
on fast machines. Now asserts correct query results across 100 repeated
CompareColumns queries, verifying functional correctness rather than
wall-clock time.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# [1.1.0-beta.7](v1.1.0-beta.6...v1.1.0-beta.7) (2026-05-26)

### Bug Fixes

* **bulk-delete:** copy RecurrencePattern and StartDateTime to asyncoperation ([97d08d0](97d08d0))
* **bulk-delete:** omit recurrencepattern and recurrencestarttime when not set ([665a695](665a695))
* **query:** fix 4 critical query engine bugs ([9bcbdc2](9bcbdc2))
* remove 14 redundant using directives ([66f139b](66f139b))
* remove 5 unused local variables ([9ef79de](9ef79de))
* remove redundant System.Reflection qualifier ([c11bd75](c11bd75))
* replace obsolete HasCount() with Count().IsEqualTo() ([24d9719](24d9719))
* resolve ambiguous XML doc comment reference ([f3a3928](f3a3928))
* use Count property instead of Count() method ([1577b52](1577b52))
* validate relationship metadata matches parent entity in DeepInsertProcessor ([fdafece](fdafece))

### Features

* **query:** implement CompareColumns and MatchFirstRowUsingCrossApply ([7376e02](7376e02))
* **query:** support FilterExpression.AnyAllFilterLinkEntity and JoinOperator.All/NotAll ([628fd01](628fd01))
* support deep insert (RelatedEntities) in CreateFake and UpsertFake ([07ef938](07ef938))
ProcessOneToMany now handles both directions:
- Parent is Referenced side → sets FK on children (existing behavior)
- Parent is Referencing side → creates child first, then sets FK on parent

This fixes nested deep inserts like Calendar → CalendarRule → InnerCalendar
where the inner relationship goes from the Referencing to the Referenced side.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A lookup attribute can only reference one record. The N:1 (reverse)
branch now throws an InvalidArgument fault when multiple children are
provided, preventing silent data loss where only the last child would
be linked. Also validates that the child's logical name matches
metadata.ReferencedEntity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# [1.1.0-beta.8](v1.1.0-beta.7...v1.1.0-beta.8) (2026-05-26)

### Bug Fixes

* enforce single-child and entity type validation for N:1 deep insert ([4242368](4242368))
* support reverse-direction (ManyToOne) nested deep insert ([d05ff50](d05ff50))
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR prepares the next beta release of Digitall.Dataverse.Testing by replacing environment-variable defaults with per-service options, broadening fake Dataverse request/query support, and adding extensive TUnit coverage for the new behavior.

Changes:

  • Introduces FakeDataverseOptions and builder helpers for current user, business unit, fiscal year start, and retrieve limits.
  • Expands request fakes and query processing, including deep insert, metadata retrieval, FetchXml/QueryExpression conversion, advanced joins, aggregate fixes, and audit/default field behavior.
  • Updates documentation, package references, analyzer scope, and test guidance for the release.

Reviewed changes

Copilot reviewed 84 out of 86 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
.gitignore Adds local tool/output ignores.
AGENTS.md Documents TUnit --treenode-filter usage.
Directory.Build.props Bumps package/release version metadata.
README.md Documents new options, request fakes, joins, and deep insert.
qodana.yaml Adjusts Qodana exclusions.
src/Digitall.Dataverse.Testing/Digitall.Dataverse.Testing.csproj Removes source generator package.
src/Digitall.Dataverse.Testing/EntityTypeResolver.cs Adds metadata-only entity support and proxy conversion cache.
src/Digitall.Dataverse.Testing/Errors/ErrorCodes.cs Adds MessageDoesNotExist.
src/Digitall.Dataverse.Testing/Extensions/DateTimeExtensions.cs Reworks week boundary helpers.
src/Digitall.Dataverse.Testing/Extensions/EntityExtensions.cs Updates cloning/projection and aliased join handling.
src/Digitall.Dataverse.Testing/Extensions/FakeDataverseBuilderExtensions.cs Adds option-setting builder methods.
src/Digitall.Dataverse.Testing/FakeDataverseOptions.cs Adds per-service configuration options.
src/Digitall.Dataverse.Testing/Logic/Queries/ExpressionProcessor.cs Adds any/all filter support and idempotent alias handling.
src/Digitall.Dataverse.Testing/Logic/Queries/FetchProcessor.cs Adds FetchXml operator/link handling and bool fallback parsing.
src/Digitall.Dataverse.Testing/Logic/Queries/LinkedEntitiesProcessor.cs Adds advanced join operators.
src/Digitall.Dataverse.Testing/Logic/Queries/QueryExpressionExtensions.cs Supports recursive alias lookup.
src/Digitall.Dataverse.Testing/Logic/Queries/QueryProcessor.cs Updates aggregate validation/error handling and ordering.
src/Digitall.Dataverse.Testing/Logic/Queries/Validators.cs Allows null filter validation input.
src/Digitall.Dataverse.Testing/Logic/XrmOrderByAttributeComparer.cs Refactors ordering comparisons and aliased values.
src/Digitall.Dataverse.Testing/OrganizationRequests/AssociateFake.cs Implements relationship-aware associate behavior.
src/Digitall.Dataverse.Testing/OrganizationRequests/BulkDeleteFake.cs Populates async operation metadata.
src/Digitall.Dataverse.Testing/OrganizationRequests/CreateFake.cs Routes create through core logic and deep insert.
src/Digitall.Dataverse.Testing/OrganizationRequests/DeepInsertProcessor.cs Adds deep insert helper.
src/Digitall.Dataverse.Testing/OrganizationRequests/DeleteFake.cs Uses delete core logic.
src/Digitall.Dataverse.Testing/OrganizationRequests/DisassociateFake.cs Implements M:N disassociate behavior.
src/Digitall.Dataverse.Testing/OrganizationRequests/FetchXmlToQueryExpressionFake.cs Adds FetchXml-to-query request fake.
src/Digitall.Dataverse.Testing/OrganizationRequests/QueryExpressionToFetchXmlFake.cs Adds query-to-FetchXml request fake.
src/Digitall.Dataverse.Testing/OrganizationRequests/RetrieveAllEntitiesFake.cs Adds all-metadata retrieval fake.
src/Digitall.Dataverse.Testing/OrganizationRequests/RetrieveFake.cs Adds related entity retrieval support.
src/Digitall.Dataverse.Testing/OrganizationRequests/RetrieveMultipleFake.cs Uses options for paging and improves faults/projection.
src/Digitall.Dataverse.Testing/OrganizationRequests/UpdateFake.cs Uses update core logic.
src/Digitall.Dataverse.Testing/OrganizationRequests/UpsertFake.cs Adds deep insert handling on upsert paths.
src/Digitall.Dataverse.Testing/OrganizationRequests/WhoAmIFake.cs Uses service options for identity data.
src/Digitall.Dataverse.Testing/PluginExecutionContextBuilder.cs Uses fake service options for default user ID.
src/Digitall.Dataverse.Testing/packages.lock.json Updates source dependency lock state.
tests/Digitall.Dataverse.Testing.Tests/.env Removes environment-based test configuration content.
tests/Digitall.Dataverse.Testing.Tests/Digitall.Dataverse.Testing.Tests.csproj Updates test dependencies and removes DotNetEnv.
tests/Digitall.Dataverse.Testing.Tests/Errors/ErrorFactoryTests.cs Adds error factory tests.
tests/Digitall.Dataverse.Testing.Tests/Extensions/BuilderExtensionsTests.cs Adds max retrieve count builder tests.
tests/Digitall.Dataverse.Testing.Tests/Extensions/DateTimeExtensionsTests.cs Updates date extension coverage.
tests/Digitall.Dataverse.Testing.Tests/Extensions/EntityExtensionsTests.cs Adds clone independence coverage.
tests/Digitall.Dataverse.Testing.Tests/Extensions/PluginExecutionContextBuilderExtensionsTests.cs Removes env precedence tests.
tests/Digitall.Dataverse.Testing.Tests/FakeDataverseBuilderTests.cs Adds option builder tests.
tests/Digitall.Dataverse.Testing.Tests/FakeOrganizationServiceTests.cs Adds metadata, audit, owner, and update merge tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/AggregateFetchXmlBehaviorTests.cs Adds aggregate behavior coverage.
tests/Digitall.Dataverse.Testing.Tests/Logic/AggregateFetchXmlValidationTests.cs Adds aggregate validation coverage.
tests/Digitall.Dataverse.Testing.Tests/Logic/CompareColumnsTests.cs Adds compare-columns query tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/CrossApplyJoinTests.cs Adds cross-apply join tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/ExpressionProcessorTests.cs Adds filter and alias reuse tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/FetchProcessorTests.cs Adds FetchXml conversion/query tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/LinkEntityColumnProjectionTests.cs Adds linked column projection tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/NaturalJoinTests.cs Adds natural join tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/QueryBugsTests.cs Adds regression tests for query fixes.
tests/Digitall.Dataverse.Testing.Tests/Logic/QueryProcessorTests.cs Adds query orchestration tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/QueryTests.cs Replaces env setup with options and adds fiscal/user tests.
tests/Digitall.Dataverse.Testing.Tests/Logic/ValidatorsTests.cs Adds alias validator tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/AssignRequestFakeTests.cs Adds assign fake tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/AssociateFakeTests.cs Adds associate fake tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/BulkDeleteFakeTests.cs Adds bulk delete fake tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/DeleteFakeTests.cs Adds delete fake tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/DisassociateFakeTests.cs Adds disassociate fake tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/ExecuteTransactionFakeTests.cs Adds transaction fake tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/FetchXmlToQueryExpressionTests.cs Adds FetchXml conversion request tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/OrganizationRequestFakeTests.cs Adds assign preservation coverage.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/QueryExpressionToFetchXmlTests.cs Adds query conversion request tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/RetrieveAllEntitiesTests.cs Adds all metadata retrieval tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/RetrieveEntityFakeTests.cs Adds entity metadata retrieval tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/RetrieveMultipleFetchXmlBoolTests.cs Adds bool FetchXml regression tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/SetStateFakeTests.cs Adds state/status fake tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/UpdateFakeTests.cs Adds update fake tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/UpsertFakeDeepInsertTests.cs Adds upsert deep insert tests.
tests/Digitall.Dataverse.Testing.Tests/OrganizationRequests/WhoAmITests.cs Removes DotNetEnv setup.
tests/Digitall.Dataverse.Testing.Tests/PluginExecutionContextBuilderTests.cs Updates user ID default tests and formatting.
tests/Digitall.Dataverse.Testing.Tests/packages.lock.json Updates test dependency lock state.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

writer.WriteAttributeString("alias", link.EntityAlias);
}

writer.WriteAttributeString("link-type", link.JoinOperator == JoinOperator.LeftOuter ? "outer" : "inner");
Comment on lines +231 to +232
if (values.Count == 1)
{
{
throw new Exception("Missing name for attribute in aggregate fetch xml");
}
// logicalName is guaranteed non-empty by ValidateXmlDocument (requires "name" on <attribute>)
{
throw new Exception("An alias is required for an order clause for an aggregate Query.");
}
// alias is guaranteed present by ValidateXmlDocument (requires "alias" on <order> in aggregate)
var parentRef = new EntityReference(parentLogicalName, parentId);

foreach (var child in children.Entities)
{
Comment on lines +139 to +144
var isFrom1To2 = parentLogicalName == metadata.Entity1LogicalName;
var fromAttribute = isFrom1To2 ? metadata.Entity1IntersectAttribute : metadata.Entity2IntersectAttribute;
var toAttribute = isFrom1To2 ? metadata.Entity2IntersectAttribute : metadata.Entity1IntersectAttribute;

foreach (var child in children.Entities)
{
Comment on lines 19 to 22
if (user != null)
{
var buId = GetBusinessUnitId(user);
var buId = GetBusinessUnitId(user) ?? state.Options.BusinessUnitId;
results.Add("BusinessUnitId", buId);
@PepperPix PepperPix marked this pull request as draft May 26, 2026 10:07
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.

4 participants