diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 8b10e80..4560f06 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -62,7 +62,7 @@ jobs:
failed=0
for tfm in "${frameworks[@]}"; do
echo "::group::Testing $tfm"
- if ! dotnet test src/ByteAether.Ulid.slnx --configuration CI-Debug -p:ImplTargetFramework=$tfm --verbosity normal --logger "trx;LogFileName=results-$tfm.trx"; then
+ if ! (cd src && dotnet test ByteAether.Ulid.slnx --configuration CI-Debug -p:ImplTargetFramework=$tfm --report-trx --report-trx-filename "results-$tfm.trx"); then
echo "❌ Tests failed for $tfm"
failed=1
fi
diff --git a/src/Dapper.IntegrationTests/Dapper.IntegrationTests.csproj b/src/Dapper.IntegrationTests/Dapper.IntegrationTests.csproj
index 5473d3c..9decdd7 100644
--- a/src/Dapper.IntegrationTests/Dapper.IntegrationTests.csproj
+++ b/src/Dapper.IntegrationTests/Dapper.IntegrationTests.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Dapper/Dapper.Impl.csproj b/src/Dapper/Dapper.Impl.csproj
index e87c102..f1a58c2 100644
--- a/src/Dapper/Dapper.Impl.csproj
+++ b/src/Dapper/Dapper.Impl.csproj
@@ -30,11 +30,11 @@
-
+
-
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 4eda8cb..61464e5 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -50,13 +50,14 @@
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
new file mode 100644
index 0000000..deffec2
--- /dev/null
+++ b/src/Directory.Packages.props
@@ -0,0 +1,19 @@
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/EFCore.IntegrationTests/EFCore.IntegrationTests.csproj b/src/EFCore.IntegrationTests/EFCore.IntegrationTests.csproj
index 7e87269..4e74a9d 100644
--- a/src/EFCore.IntegrationTests/EFCore.IntegrationTests.csproj
+++ b/src/EFCore.IntegrationTests/EFCore.IntegrationTests.csproj
@@ -11,11 +11,11 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/src/EFCore.IntegrationTests/UlidEntityFrameworkIntegrationTests.cs b/src/EFCore.IntegrationTests/UlidEntityFrameworkIntegrationTests.cs
index cd65c01..1cdd31b 100644
--- a/src/EFCore.IntegrationTests/UlidEntityFrameworkIntegrationTests.cs
+++ b/src/EFCore.IntegrationTests/UlidEntityFrameworkIntegrationTests.cs
@@ -51,16 +51,16 @@ public async Task EFCore_ShouldSuccessfullyRoundTrip_BothNonNullAndNullableUlids
await using (var writeContext = CreateContext(format))
{
writeContext.TestEntities.Add(entity);
- await writeContext.SaveChangesAsync();
+ await writeContext.SaveChangesAsync(TestContext.Current.CancellationToken);
}
// Act - Step 2: Read back from an isolated context instance & Query via Null comparison
await using (var readContext = CreateContext(format))
{
- var dbEntity = await readContext.TestEntities.FirstOrDefaultAsync(e => e.SystemUlid == originalUlid);
+ var dbEntity = await readContext.TestEntities.FirstOrDefaultAsync(e => e.SystemUlid == originalUlid, cancellationToken: TestContext.Current.CancellationToken);
// Verify querying directly by matching a null column works flawlessly
- var nullQueryEntity = await readContext.TestEntities.FirstOrDefaultAsync(e => e.NullableUlid == null);
+ var nullQueryEntity = await readContext.TestEntities.FirstOrDefaultAsync(e => e.NullableUlid == null, cancellationToken: TestContext.Current.CancellationToken);
// Assert
Assert.NotNull(dbEntity);
@@ -72,13 +72,13 @@ public async Task EFCore_ShouldSuccessfullyRoundTrip_BothNonNullAndNullableUlids
var updatedUlid = Ulid.New();
dbEntity.NullableUlid = updatedUlid;
readContext.TestEntities.Update(dbEntity);
- await readContext.SaveChangesAsync();
+ await readContext.SaveChangesAsync(TestContext.Current.CancellationToken);
}
// Act - Step 4: Validate update retrieval
await using (var verifyContext = CreateContext(format))
{
- var dbEntity = await verifyContext.TestEntities.FirstOrDefaultAsync();
+ var dbEntity = await verifyContext.TestEntities.FirstOrDefaultAsync(cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(dbEntity);
Assert.Equal(originalUlid, dbEntity.SystemUlid);
Assert.NotNull(dbEntity.NullableUlid);
@@ -86,13 +86,13 @@ public async Task EFCore_ShouldSuccessfullyRoundTrip_BothNonNullAndNullableUlids
// Step 5: Test reversing a value back to null (Null-to-Null round trip)
dbEntity.NullableUlid = null;
verifyContext.TestEntities.Update(dbEntity);
- await verifyContext.SaveChangesAsync();
+ await verifyContext.SaveChangesAsync(TestContext.Current.CancellationToken);
}
// Act - Step 6: Final check that reverting to null persisted properly
await using (var finalVerifyContext = CreateContext(format))
{
- var dbEntity = await finalVerifyContext.TestEntities.FirstOrDefaultAsync();
+ var dbEntity = await finalVerifyContext.TestEntities.FirstOrDefaultAsync(cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(dbEntity);
Assert.Null(dbEntity.NullableUlid);
}
@@ -111,12 +111,12 @@ public async Task EFCore_ShouldTranslateLINQRangeQueries_ProperlyWithParameters(
var maxUlid = Ulid.MaxAt(DateTimeOffset.UtcNow.AddDays(1));
context.TestEntities.Add(new(){ SystemUlid = targetUlid });
- await context.SaveChangesAsync();
+ await context.SaveChangesAsync(TestContext.Current.CancellationToken);
// Act - Evaluate if EF translation properly maps parameter types to database lookups
var results = await context.TestEntities
.Where(e => e.SystemUlid >= minUlid && e.SystemUlid <= maxUlid)
- .ToListAsync();
+ .ToListAsync(cancellationToken: TestContext.Current.CancellationToken);
// Assert
Assert.Single(results);
@@ -135,18 +135,18 @@ public async Task EFCore_ShouldSuccessfullyProject_UlidToAnonymousAndDtoTypes(Ul
var targetUlid = Ulid.New();
context.TestEntities.Add(new() { SystemUlid = targetUlid, NullableUlid = Ulid.New() });
- await context.SaveChangesAsync();
+ await context.SaveChangesAsync(TestContext.Current.CancellationToken);
context.ChangeTracker.Clear();
// Act - Step 1: Project into an anonymous type
var anonymousResult = await context.TestEntities
.Select(e => new { e.Id, e.SystemUlid, e.NullableUlid })
- .FirstOrDefaultAsync(e => e.SystemUlid == targetUlid);
+ .FirstOrDefaultAsync(e => e.SystemUlid == targetUlid, cancellationToken: TestContext.Current.CancellationToken);
// Act - Step 2: Project directly into a raw primitive/value type collection
var rawUlidList = await context.TestEntities
.Select(e => e.SystemUlid)
- .ToListAsync();
+ .ToListAsync(cancellationToken: TestContext.Current.CancellationToken);
// Assert
Assert.NotNull(anonymousResult);
@@ -172,7 +172,7 @@ public async Task EFCore_ShouldTranslateContainsQuery_WhenUsingUlidCollections(U
new TestEntity { SystemUlid = Ulid.New(), NullableUlid = targetUlid },
new TestEntity { SystemUlid = Ulid.New(), NullableUlid = null }
);
- await context.SaveChangesAsync();
+ await context.SaveChangesAsync(TestContext.Current.CancellationToken);
context.ChangeTracker.Clear();
// Strategy: Include null directly inside the searchable target criteria collection
@@ -181,7 +181,7 @@ public async Task EFCore_ShouldTranslateContainsQuery_WhenUsingUlidCollections(U
// Act
var results = await context.TestEntities
.Where(e => searchCriteria.Contains(e.NullableUlid))
- .ToListAsync();
+ .ToListAsync(cancellationToken: TestContext.Current.CancellationToken);
// Assert
Assert.Equal(2, results.Count);
@@ -231,10 +231,10 @@ public async Task SchemaCreation_ShouldGenerateCorrectDatabaseColumnTypes(UlidSt
await using var command = _connection.CreateCommand();
command.CommandText = "PRAGMA table_info(TestEntities);";
- await using var reader = await command.ExecuteReaderAsync();
+ await using var reader = await command.ExecuteReaderAsync(TestContext.Current.CancellationToken);
var foundSystemUlid = false;
- while (await reader.ReadAsync())
+ while (await reader.ReadAsync(TestContext.Current.CancellationToken))
{
var columnName = reader.GetString(reader.GetOrdinal("name"));
if (columnName != nameof(TestEntity.SystemUlid))
@@ -261,9 +261,9 @@ public async Task EFCore_ShouldMaintainChronologicalOrder_WhenOrderingByUlid(Uli
await using var context = CreateContext(format);
var first = Ulid.New();
- await Task.Delay(10); // Ensure timestamp progression if relying on machine clock
+ await Task.Delay(10, TestContext.Current.CancellationToken); // Ensure timestamp progression if relying on machine clock
var second = Ulid.New();
- await Task.Delay(10);
+ await Task.Delay(10, TestContext.Current.CancellationToken);
var third = Ulid.New();
// Add them completely out of order
@@ -272,10 +272,10 @@ public async Task EFCore_ShouldMaintainChronologicalOrder_WhenOrderingByUlid(Uli
new TestEntity { SystemUlid = third },
new TestEntity { SystemUlid = first }
);
- await context.SaveChangesAsync();
+ await context.SaveChangesAsync(TestContext.Current.CancellationToken);
// Act
- var orderedList = await context.TestEntities.OrderBy(e => e.SystemUlid).ToListAsync();
+ var orderedList = await context.TestEntities.OrderBy(e => e.SystemUlid).ToListAsync(cancellationToken: TestContext.Current.CancellationToken);
// Assert
Assert.Equal(3, orderedList.Count);
@@ -305,7 +305,7 @@ public async Task EFCore_ShouldSuccessfullyExecuteJoins_OnUlidProperties(UlidSto
context.TestEntities.Add(parentEntity);
context.Set().Add(childEntity);
- await context.SaveChangesAsync();
+ await context.SaveChangesAsync(TestContext.Current.CancellationToken);
context.ChangeTracker.Clear();
// Act - Explicit inner join execution over ULID properties
@@ -316,7 +316,7 @@ public async Task EFCore_ShouldSuccessfullyExecuteJoins_OnUlidProperties(UlidSto
child => child.ParentSystemUlid,
(parent, child) => new { parent.Id, parent.SystemUlid, child.Description }
)
- .FirstOrDefaultAsync(x => x.SystemUlid == parentUlid);
+ .FirstOrDefaultAsync(x => x.SystemUlid == parentUlid, cancellationToken: TestContext.Current.CancellationToken);
// Assert
Assert.NotNull(joinResult);
@@ -336,18 +336,18 @@ public async Task EFCore_ShouldNotDetectFalseChanges_WhenEntityIsLoadedButUnmodi
await using (var setupContext = CreateContext(format))
{
setupContext.TestEntities.Add(new() { SystemUlid = originalUlid, NullableUlid = Ulid.New() });
- await setupContext.SaveChangesAsync();
+ await setupContext.SaveChangesAsync(TestContext.Current.CancellationToken);
}
// Act & Assert
await using (var trackingContext = CreateContext(format))
{
// Load the entity completely into memory state tracking
- var dbEntity = await trackingContext.TestEntities.FirstOrDefaultAsync(e => e.SystemUlid == originalUlid);
+ var dbEntity = await trackingContext.TestEntities.FirstOrDefaultAsync(e => e.SystemUlid == originalUlid, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(dbEntity);
// Attempt a Save without modifying any structural data properties
- var affectedRows = await trackingContext.SaveChangesAsync();
+ var affectedRows = await trackingContext.SaveChangesAsync(TestContext.Current.CancellationToken);
// Verify that EF Core understands the model is completely clean
// (Returns 0 updates executed to the underlying data provider)
diff --git a/src/EFCore/EFCore.Impl.csproj b/src/EFCore/EFCore.Impl.csproj
index 63cbda9..115bc6f 100644
--- a/src/EFCore/EFCore.Impl.csproj
+++ b/src/EFCore/EFCore.Impl.csproj
@@ -30,13 +30,13 @@
-
+
build;analyzers
-
+
diff --git a/src/LinqToDB.IntegrationTests/LinqToDB.IntegrationTests.csproj b/src/LinqToDB.IntegrationTests/LinqToDB.IntegrationTests.csproj
index cc419a1..d73a488 100644
--- a/src/LinqToDB.IntegrationTests/LinqToDB.IntegrationTests.csproj
+++ b/src/LinqToDB.IntegrationTests/LinqToDB.IntegrationTests.csproj
@@ -11,8 +11,8 @@
-
-
+
+
diff --git a/src/LinqToDB.IntegrationTests/UlidLinqToDbIntegrationTests.cs b/src/LinqToDB.IntegrationTests/UlidLinqToDbIntegrationTests.cs
index ea164a2..71576af 100644
--- a/src/LinqToDB.IntegrationTests/UlidLinqToDbIntegrationTests.cs
+++ b/src/LinqToDB.IntegrationTests/UlidLinqToDbIntegrationTests.cs
@@ -75,14 +75,14 @@ public async Task LinqToDB_ShouldSuccessfullyRoundTrip_BothNonNullAndNullableUli
// Act - Step 1: Write to database
await using (var writeContext = CreateConnection(format))
{
- await writeContext.InsertAsync(entity);
+ await writeContext.InsertAsync(entity, token: TestContext.Current.CancellationToken);
}
// Act - Step 2: Read back via an isolated, stateless connection
await using (var readContext = CreateConnection(format))
{
var dbEntity = await readContext.GetTable()
- .FirstOrDefaultAsync(e => e.SystemUlid == originalUlid);
+ .FirstOrDefaultAsync(e => e.SystemUlid == originalUlid, token: TestContext.Current.CancellationToken);
// Assert
Assert.NotNull(dbEntity);
@@ -92,26 +92,26 @@ public async Task LinqToDB_ShouldSuccessfullyRoundTrip_BothNonNullAndNullableUli
// Step 3: Test update conversion behavior on nullable property types
var updatedUlid = Ulid.New();
dbEntity.NullableUlid = updatedUlid;
- await readContext.UpdateAsync(dbEntity);
+ await readContext.UpdateAsync(dbEntity, token: TestContext.Current.CancellationToken);
}
// Act - Step 4: Validate update persistence
await using (var verifyContext = CreateConnection(format))
{
- var dbEntity = await verifyContext.GetTable().FirstOrDefaultAsync();
+ var dbEntity = await verifyContext.GetTable().FirstOrDefaultAsync(token: TestContext.Current.CancellationToken);
Assert.NotNull(dbEntity);
Assert.Equal(originalUlid, dbEntity.SystemUlid);
Assert.NotNull(dbEntity.NullableUlid);
// Step 5: Test reversing a value back to null (Null-to-Null round trip)
dbEntity.NullableUlid = null;
- await verifyContext.UpdateAsync(dbEntity);
+ await verifyContext.UpdateAsync(dbEntity, token: TestContext.Current.CancellationToken);
}
// Act - Step 6: Final check that reverting to null persisted properly
await using (var finalVerifyContext = CreateConnection(format))
{
- var dbEntity = await finalVerifyContext.GetTable().FirstOrDefaultAsync();
+ var dbEntity = await finalVerifyContext.GetTable().FirstOrDefaultAsync(token: TestContext.Current.CancellationToken);
Assert.NotNull(dbEntity);
Assert.Null(dbEntity.NullableUlid);
}
@@ -131,12 +131,12 @@ public async Task LinqToDB_ShouldTranslateLINQRangeQueries_ProperlyWithParameter
var targetUlid = Ulid.New();
var maxUlid = Ulid.MaxAt(DateTimeOffset.UtcNow.AddDays(1));
- await context.InsertAsync(new TestEntity { SystemUlid = targetUlid });
+ await context.InsertAsync(new TestEntity { SystemUlid = targetUlid }, token: TestContext.Current.CancellationToken);
// Act - Validate that LinqToDB command tree translates logical bounds matching type conversions
var results = await context.GetTable()
.Where(e => e.SystemUlid >= minUlid && e.SystemUlid <= maxUlid)
- .ToListAsync();
+ .ToListAsync(token: TestContext.Current.CancellationToken);
// Assert
Assert.Single(results);
@@ -154,17 +154,17 @@ public async Task LinqToDB_ShouldSuccessfullyProject_UlidToAnonymousAndDtoTypes(
await using var context = CreateConnection(format);
var targetUlid = Ulid.New();
- await context.InsertAsync(new TestEntity { SystemUlid = targetUlid, NullableUlid = Ulid.New() });
+ await context.InsertAsync(new TestEntity { SystemUlid = targetUlid, NullableUlid = Ulid.New() }, token: TestContext.Current.CancellationToken);
// Act - Step 1: Query compilation evaluation over anonymous shape allocations
var anonymousResult = await context.GetTable()
.Select(e => new { e.Id, e.SystemUlid, e.NullableUlid })
- .FirstOrDefaultAsync(e => e.SystemUlid == targetUlid);
+ .FirstOrDefaultAsync(e => e.SystemUlid == targetUlid, token: TestContext.Current.CancellationToken);
// Act - Step 2: Extract scalar data projections
var rawUlidList = await context.GetTable()
.Select(e => e.SystemUlid)
- .ToListAsync();
+ .ToListAsync(token: TestContext.Current.CancellationToken);
// Assert
Assert.NotNull(anonymousResult);
@@ -186,8 +186,8 @@ public async Task LinqToDB_ShouldTranslateContainsQuery_WhenUsingUlidCollections
var targetUlid = Ulid.New();
- await context.InsertAsync(new TestEntity { NullableUlid = targetUlid });
- await context.InsertAsync(new TestEntity { NullableUlid = null });
+ await context.InsertAsync(new TestEntity { NullableUlid = targetUlid }, token: TestContext.Current.CancellationToken);
+ await context.InsertAsync(new TestEntity { NullableUlid = null }, token: TestContext.Current.CancellationToken);
// Strategy: Include null directly inside the searchable target criteria collection
var searchCriteria = new Ulid?[] { targetUlid, null };
@@ -195,7 +195,7 @@ public async Task LinqToDB_ShouldTranslateContainsQuery_WhenUsingUlidCollections
// Act
var results = await context.GetTable()
.Where(e => searchCriteria.Contains(e.NullableUlid))
- .ToListAsync();
+ .ToListAsync(token: TestContext.Current.CancellationToken);
// Assert
Assert.Equal(2, results.Count);
@@ -214,20 +214,20 @@ public async Task LinqToDB_ShouldMaintainChronologicalOrder_WhenOrderingByUlid(U
await using var context = CreateConnection(format);
var first = Ulid.New();
- await Task.Delay(10); // Enforce clear hardware timestamp increments
+ await Task.Delay(10, TestContext.Current.CancellationToken); // Enforce clear hardware timestamp increments
var second = Ulid.New();
- await Task.Delay(10);
+ await Task.Delay(10, TestContext.Current.CancellationToken);
var third = Ulid.New();
// Insert scrambled chronological payloads
- await context.InsertAsync(new TestEntity { SystemUlid = second });
- await context.InsertAsync(new TestEntity { SystemUlid = third });
- await context.InsertAsync(new TestEntity { SystemUlid = first });
+ await context.InsertAsync(new TestEntity { SystemUlid = second }, token: TestContext.Current.CancellationToken);
+ await context.InsertAsync(new TestEntity { SystemUlid = third }, token: TestContext.Current.CancellationToken);
+ await context.InsertAsync(new TestEntity { SystemUlid = first }, token: TestContext.Current.CancellationToken);
// Act
var orderedList = await context.GetTable()
.OrderBy(e => e.SystemUlid)
- .ToListAsync();
+ .ToListAsync(token: TestContext.Current.CancellationToken);
// Assert
Assert.Equal(3, orderedList.Count);
@@ -247,8 +247,8 @@ public async Task LinqToDB_ShouldSuccessfullyExecuteJoins_OnUlidProperties(UlidS
await using var context = CreateConnection(format);
var parentUlid = Ulid.New();
- await context.InsertAsync(new TestEntity { SystemUlid = parentUlid });
- await context.InsertAsync(new RelatedChildEntity { ParentSystemUlid = parentUlid, Description = "Child linked via ULID" });
+ await context.InsertAsync(new TestEntity { SystemUlid = parentUlid }, token: TestContext.Current.CancellationToken);
+ await context.InsertAsync(new RelatedChildEntity { ParentSystemUlid = parentUlid, Description = "Child linked via ULID" }, token: TestContext.Current.CancellationToken);
// Act - Enforce expression evaluation trees across relational predicates
var joinResult = await context.GetTable()
@@ -258,7 +258,7 @@ public async Task LinqToDB_ShouldSuccessfullyExecuteJoins_OnUlidProperties(UlidS
child => child.ParentSystemUlid,
(parent, child) => new { parent.Id, parent.SystemUlid, child.Description }
)
- .FirstOrDefaultAsync(x => x.SystemUlid == parentUlid);
+ .FirstOrDefaultAsync(x => x.SystemUlid == parentUlid, token: TestContext.Current.CancellationToken);
// Assert
Assert.NotNull(joinResult);
diff --git a/src/LinqToDB/LinqToDB.Impl.csproj b/src/LinqToDB/LinqToDB.Impl.csproj
index 51d09d7..52a3cb7 100644
--- a/src/LinqToDB/LinqToDB.Impl.csproj
+++ b/src/LinqToDB/LinqToDB.Impl.csproj
@@ -29,13 +29,13 @@
-
+
build;analyzers
-
+
diff --git a/src/Ulid.Benchmarks/Benchmarks.csproj b/src/Ulid.Benchmarks/Benchmarks.csproj
index 7a49738..817172a 100644
--- a/src/Ulid.Benchmarks/Benchmarks.csproj
+++ b/src/Ulid.Benchmarks/Benchmarks.csproj
@@ -9,10 +9,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Ulid.Tests/Tests.csproj b/src/Ulid.Tests/Tests.csproj
index a9feaca..dea037a 100644
--- a/src/Ulid.Tests/Tests.csproj
+++ b/src/Ulid.Tests/Tests.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/src/Ulid/Impl.csproj b/src/Ulid/Impl.csproj
index 179c56a..e042ca1 100644
--- a/src/Ulid/Impl.csproj
+++ b/src/Ulid/Impl.csproj
@@ -26,12 +26,12 @@
-
-
+
+
-
+
diff --git a/src/global.json b/src/global.json
new file mode 100644
index 0000000..3140116
--- /dev/null
+++ b/src/global.json
@@ -0,0 +1,5 @@
+{
+ "test": {
+ "runner": "Microsoft.Testing.Platform"
+ }
+}