diff --git a/src/DeltaLake/Bridge/ByteArrayRef.cs b/src/DeltaLake/Bridge/ByteArrayRef.cs index 3a2854f7..e99c1a8b 100644 --- a/src/DeltaLake/Bridge/ByteArrayRef.cs +++ b/src/DeltaLake/Bridge/ByteArrayRef.cs @@ -104,7 +104,11 @@ public static RentedByteArrayRef RentUtf8(string s) } var bytes = ArrayPool.Shared.Rent(StrictUTF8.GetByteCount(s)); +#if NETCOREAPP var length = StrictUTF8.GetBytes(s, bytes); +#else + var length = StrictUTF8.GetBytes(s, 0, s.Length, bytes, 0); +#endif return new RentedByteArrayRef(new ByteArrayRef(bytes.AsMemory(0, length)), bytes, ArrayPool.Shared); } diff --git a/src/DeltaLake/Bridge/RecordBatchReader.cs b/src/DeltaLake/Bridge/RecordBatchReader.cs index 4f4f3344..138a6467 100644 --- a/src/DeltaLake/Bridge/RecordBatchReader.cs +++ b/src/DeltaLake/Bridge/RecordBatchReader.cs @@ -26,11 +26,19 @@ public ValueTask ReadNextRecordBatchAsync(System.Threading.Cancella { if (_enumerator.MoveNext()) { +#if NETCOREAPP return ValueTask.FromResult(_enumerator.Current); +#else + return new ValueTask(_enumerator.Current); +#endif } #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#if NETCOREAPP return ValueTask.FromResult(default); +#else + return new ValueTask(default(RecordBatch)); +#endif #pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } } diff --git a/src/DeltaLake/Bridge/Runtime.cs b/src/DeltaLake/Bridge/Runtime.cs index ede5cff2..d34625b4 100644 --- a/src/DeltaLake/Bridge/Runtime.cs +++ b/src/DeltaLake/Bridge/Runtime.cs @@ -52,7 +52,11 @@ internal virtual async Task LoadTablePtrAsync( System.Threading.CancellationToken cancellationToken) { var buffer = ArrayPool.Shared.Rent(System.Text.Encoding.UTF8.GetByteCount(options.TableLocation)); +#if NETCOREAPP var encodedLength = System.Text.Encoding.UTF8.GetBytes(options.TableLocation, buffer); +#else + var encodedLength = System.Text.Encoding.UTF8.GetBytes(options.TableLocation, 0, options.TableLocation.Length, buffer, 0); +#endif try { return await LoadTablePtrAsync(buffer.AsMemory(0, encodedLength), options, cancellationToken).ConfigureAwait(false); diff --git a/src/DeltaLake/Bridge/Table.cs b/src/DeltaLake/Bridge/Table.cs index 69c93b08..155fbfbc 100644 --- a/src/DeltaLake/Bridge/Table.cs +++ b/src/DeltaLake/Bridge/Table.cs @@ -17,6 +17,10 @@ namespace DeltaLake.Bridge /// internal class Table : SafeHandle { +#if !NETCOREAPP + private unsafe delegate void MetadataRelease(Interop.TableMetadata* metadata); +#endif + internal static readonly ByteArrayRef SaveModeAppend = ByteArrayRef.FromUTF8("append"); internal static readonly ByteArrayRef SaveModeOverwrite = ByteArrayRef.FromUTF8("overwrite"); @@ -563,7 +567,11 @@ internal virtual DeltaLake.Table.TableMetadata Metadata() } finally { +#if NETCOREAPP var release = (delegate* unmanaged)result.metadata->release; +#else + var release = Marshal.GetDelegateForFunctionPointer(result.metadata->release); +#endif release(result.metadata); } } diff --git a/src/DeltaLake/DeltaLake.csproj b/src/DeltaLake/DeltaLake.csproj index 33bba1d8..c3f4befa 100644 --- a/src/DeltaLake/DeltaLake.csproj +++ b/src/DeltaLake/DeltaLake.csproj @@ -5,12 +5,12 @@ DeltaLake for .NET true 9.0 - true + true README.md true snupkg enable - net6.0;net8.0; + net472;net8.0; rc-1 deltalake csharp DeltaLake.Net @@ -20,6 +20,7 @@ + diff --git a/src/DeltaLake/Extensions/MarshalExtensions.cs b/src/DeltaLake/Extensions/MarshalExtensions.cs new file mode 100644 index 00000000..af4f4c51 --- /dev/null +++ b/src/DeltaLake/Extensions/MarshalExtensions.cs @@ -0,0 +1,95 @@ +// ----------------------------------------------------------------------------- +// +// Runtime-specific helpers for marshaling to and from UTF8 strings +// +// +// +// Copyright (2025) The Delta Lake Project Authors. All rights reserved. +// Licensed under the Apache license. See LICENSE file in the project root for full license information. +// +// ----------------------------------------------------------------------------- + +using System; +#pragma warning disable IDE0005 // Using directive is unnecessary. +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; +#pragma warning restore IDE0005 // Using directive is unnecessary. + +namespace DeltaLake.Extensions +{ + internal static class MarshalExtensions + { +#if !NETCOREAPP + public static unsafe string? PtrToStringUTF8(IntPtr intPtr) + { + if (intPtr == IntPtr.Zero) + { + return null; + } + + byte* source = (byte*)intPtr; + int length = 0; + + while (source[length] != 0) + { + length++; + } + + return PtrToStringUTF8(intPtr, length); + } + + public static unsafe string? PtrToStringUTF8(IntPtr intPtr, int length) + { + if (intPtr == IntPtr.Zero) + { + return null; + } + + byte[] bytes = new byte[length]; + Marshal.Copy(intPtr, bytes, 0, length); + + return Encoding.UTF8.GetString(bytes); + } + + public static unsafe IntPtr StringToCoTaskMemUTF8(string? s) + { + if (s is null) + { + return IntPtr.Zero; + } + + int nb = Encoding.UTF8.GetMaxByteCount(s.Length); + + IntPtr pMem = Marshal.AllocHGlobal(nb + 1); + + int nbWritten; + byte* pbMem = (byte*)pMem; + + fixed (char* firstChar = s) + { + nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb); + } + + pbMem[nbWritten] = 0; + + return pMem; + } +#else + public static unsafe string? PtrToStringUTF8(IntPtr intPtr) + { + return Marshal.PtrToStringUTF8(intPtr); + } + + public static IntPtr StringToCoTaskMemUTF8(string? s) + { + return Marshal.StringToCoTaskMemUTF8(s); + } + + public static unsafe string? PtrToStringUTF8(IntPtr intPtr, int length) + { + return Marshal.PtrToStringUTF8(intPtr, length); + } +#endif + } +} diff --git a/src/DeltaLake/Extensions/NetFxShims.cs b/src/DeltaLake/Extensions/NetFxShims.cs new file mode 100644 index 00000000..4dfb7802 --- /dev/null +++ b/src/DeltaLake/Extensions/NetFxShims.cs @@ -0,0 +1,126 @@ +// ----------------------------------------------------------------------------- +// +// Shims for .NET 6+ functionality that's not available to Desktop Framework +// +// +// +// Copyright (2025) The Delta Lake Project Authors. All rights reserved. +// Licensed under the Apache license. See LICENSE file in the project root for full license information. +// +// ----------------------------------------------------------------------------- + +#if !NETCOREAPP + +#pragma warning disable IDE0130 // Namespace does not match folder structure + +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace System.Runtime.CompilerServices +{ + internal static class IsExternalInit { } +} + +namespace System.Collections.Generic +{ + internal static class KeyValuePairExtensions + { + public static void Deconstruct(this KeyValuePair pair, out TKey key, out TValue value) + { + key = pair.Key; + value = pair.Value; + } + } + + internal static class DictionaryExtensions + { + public static bool TryAdd(this Dictionary dictionary, TKey key, TValue value) + { + if (dictionary.ContainsKey(key)) + { + return false; + } + dictionary.Add(key, value); + return true; + } + } +} + +namespace System.Threading.Tasks +{ + internal static class AsyncEnumerableExtensions + { + public static IEnumerable ToBlockingEnumerable(this IAsyncEnumerable source, CancellationToken cancellationToken = default) + { + IAsyncEnumerator enumerator = source.GetAsyncEnumerator(cancellationToken); + // A ManualResetEventSlim variant that lets us reuse the same + // awaiter callback allocation across the entire enumeration. + ManualResetEventWithAwaiterSupport? mres = null; + + try + { + while (true) + { +#pragma warning disable CA2012 // Use ValueTasks correctly + ValueTask moveNextTask = enumerator.MoveNextAsync(); +#pragma warning restore CA2012 // Use ValueTasks correctly + + if (!moveNextTask.IsCompleted) + { +#pragma warning disable CA2000 // Dispose objects before losing scope + (mres ??= new ManualResetEventWithAwaiterSupport()).Wait(moveNextTask.ConfigureAwait(false).GetAwaiter()); +#pragma warning restore CA2000 // Dispose objects before losing scope + Debug.Assert(moveNextTask.IsCompleted); + } + +#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits + if (!moveNextTask.Result) + { + yield break; + } +#pragma warning restore VSTHRD002 // Avoid problematic synchronous waits + + yield return enumerator.Current; + } + } + finally + { + ValueTask disposeTask = enumerator.DisposeAsync(); + + if (!disposeTask.IsCompleted) + { +#pragma warning disable CA2000 // Dispose objects before losing scope + (mres ?? new ManualResetEventWithAwaiterSupport()).Wait(disposeTask.ConfigureAwait(false).GetAwaiter()); +#pragma warning restore CA2000 // Dispose objects before losing scope + Debug.Assert(disposeTask.IsCompleted); + } + +#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits + disposeTask.GetAwaiter().GetResult(); +#pragma warning restore VSTHRD002 // Avoid problematic synchronous waits + } + } + + private sealed class ManualResetEventWithAwaiterSupport : ManualResetEventSlim + { + private readonly Action _onCompleted; + + public ManualResetEventWithAwaiterSupport() + { + _onCompleted = Set; + } + + public void Wait(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion + { + awaiter.UnsafeOnCompleted(_onCompleted); + Wait(); + Reset(); + } + } + } +} + +#pragma warning restore IDE0130 // Namespace does not match folder structure + +#endif diff --git a/src/DeltaLake/Kernel/Arrow/Extensions/ArrowContextExtensions.cs b/src/DeltaLake/Kernel/Arrow/Extensions/ArrowContextExtensions.cs index 19e3fa5f..dc9a200a 100644 --- a/src/DeltaLake/Kernel/Arrow/Extensions/ArrowContextExtensions.cs +++ b/src/DeltaLake/Kernel/Arrow/Extensions/ArrowContextExtensions.cs @@ -11,10 +11,10 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; using Apache.Arrow; using Apache.Arrow.C; using Apache.Arrow.Types; +using DeltaLake.Extensions; using DeltaLake.Kernel.Interop; using DeltaLake.Kernel.State; @@ -146,8 +146,8 @@ private static unsafe Schema AddPartitionColumnsToSchema(Apache.Arrow.Schema ori for (int i = 0; i < partitionsPtr->Len; i++) { #pragma warning disable CS8600, CS8604 // If Kernel sends us back null pointers, we are in trouble anyway - string colName = Marshal.PtrToStringUTF8((IntPtr)partitionsPtr->ColNames[i]); - string colValue = Marshal.PtrToStringUTF8((IntPtr)partitionsPtr->ColValues[i]); + string colName = MarshalExtensions.PtrToStringUTF8((IntPtr)partitionsPtr->ColNames[i]); + string colValue = MarshalExtensions.PtrToStringUTF8((IntPtr)partitionsPtr->ColValues[i]); IArrowType dataType = DeterminePartitionColumnType(colName, colValue); #pragma warning restore CS8600, CS8604 @@ -179,8 +179,8 @@ private static unsafe RecordBatch AddPartitionColumnsToRecordBatch(RecordBatch r StringArray.Builder columnBuilder = new(); #pragma warning disable CS8600 - string colName = Marshal.PtrToStringUTF8((IntPtr)partitionsPtr->ColNames[i]); - string colValue = Marshal.PtrToStringUTF8((IntPtr)partitionsPtr->ColValues[i]); + string colName = MarshalExtensions.PtrToStringUTF8((IntPtr)partitionsPtr->ColNames[i]); + string colValue = MarshalExtensions.PtrToStringUTF8((IntPtr)partitionsPtr->ColValues[i]); #pragma warning restore CS8600 Field field = new(colName, StringType.Default, nullable: true); diff --git a/src/DeltaLake/Kernel/Arrow/Handlers/ArrowFFIInterOpHandler.cs b/src/DeltaLake/Kernel/Arrow/Handlers/ArrowFFIInterOpHandler.cs index 8cc2f83e..309e9382 100644 --- a/src/DeltaLake/Kernel/Arrow/Handlers/ArrowFFIInterOpHandler.cs +++ b/src/DeltaLake/Kernel/Arrow/Handlers/ArrowFFIInterOpHandler.cs @@ -96,8 +96,8 @@ KernelBoolSlice selectionVector ) { #pragma warning disable CS8600 - string tableRoot = Marshal.PtrToStringUTF8((IntPtr)context->TableRoot)?.TrimEnd('/'); - string parquetAbsolutePath = $"{tableRoot}/{Marshal.PtrToStringUTF8((IntPtr)path.ptr, (int)path.len)}"; + string tableRoot = MarshalExtensions.PtrToStringUTF8((IntPtr)context->TableRoot)?.TrimEnd('/'); + string parquetAbsolutePath = $"{tableRoot}/{MarshalExtensions.PtrToStringUTF8((IntPtr)path.ptr, (int)path.len)}"; #pragma warning restore CS8600 (GCHandle parquetAbsolutePathHandle, IntPtr gcPinnedParquetAbsolutePathPtr) = parquetAbsolutePath.ToPinnedSBytePointer(); @@ -146,7 +146,7 @@ private static unsafe ParquetStringPartitions ParseParquetStringPartitions( for (int i = 0; i < partitionCols->Len; i++) { #pragma warning disable CS8600 - string colName = Marshal.PtrToStringUTF8((IntPtr)partitionCols->Cols[i]); + string colName = MarshalExtensions.PtrToStringUTF8((IntPtr)partitionCols->Cols[i]); #pragma warning restore CS8600 // The Kernel can currently only report String values back as @@ -166,13 +166,13 @@ private static unsafe ParquetStringPartitions ParseParquetStringPartitions( }, Marshal.GetFunctionPointerForDelegate(StringAllocatorCallbacks.AllocateString) ); - string colVal = colValPtr != null ? Marshal.PtrToStringUTF8((IntPtr)colValPtr) : String.Empty; + string colVal = colValPtr != null ? MarshalExtensions.PtrToStringUTF8((IntPtr)colValPtr) : String.Empty; #pragma warning restore CS1024, CS8629, CS8600 if (!string.IsNullOrEmpty(colName) && !string.IsNullOrEmpty(colVal)) { colNames.Add(colName); - colValues.Add(colVal); + colValues.Add(colVal!); } else { @@ -185,8 +185,8 @@ private static unsafe ParquetStringPartitions ParseParquetStringPartitions( for (int i = 0; i < colNames.Count; i++) { - colNamesPtr[i] = (byte*)Marshal.StringToCoTaskMemUTF8(colNames[i]); - colValuesPtr[i] = (byte*)Marshal.StringToCoTaskMemUTF8(colValues[i]); + colNamesPtr[i] = (byte*)MarshalExtensions.StringToCoTaskMemUTF8(colNames[i]); + colValuesPtr[i] = (byte*)MarshalExtensions.StringToCoTaskMemUTF8(colValues[i]); } return new ParquetStringPartitions diff --git a/src/DeltaLake/Kernel/Callbacks/Errors/AllocateErrorCallbacks.cs b/src/DeltaLake/Kernel/Callbacks/Errors/AllocateErrorCallbacks.cs index 407e6c4c..e91f7298 100644 --- a/src/DeltaLake/Kernel/Callbacks/Errors/AllocateErrorCallbacks.cs +++ b/src/DeltaLake/Kernel/Callbacks/Errors/AllocateErrorCallbacks.cs @@ -10,7 +10,7 @@ // ----------------------------------------------------------------------------- using System; -using System.Runtime.InteropServices; +using DeltaLake.Extensions; using DeltaLake.Kernel.Interop; namespace DeltaLake.Kernel.Callbacks.Errors @@ -31,7 +31,7 @@ internal class AllocateErrorCallbacks KernelStringSlice msg ) { - string message = Marshal.PtrToStringUTF8((IntPtr)msg.ptr) ?? string.Empty; + string message = MarshalExtensions.PtrToStringUTF8((IntPtr)msg.ptr) ?? string.Empty; throw new InvalidOperationException( $"Kernel engine error of type {etype} occurred with message: {message}" ); diff --git a/src/DeltaLake/Kernel/Callbacks/Errors/KernelReadError.cs b/src/DeltaLake/Kernel/Callbacks/Errors/KernelReadError.cs index 4e9341c8..edb6c887 100644 --- a/src/DeltaLake/Kernel/Callbacks/Errors/KernelReadError.cs +++ b/src/DeltaLake/Kernel/Callbacks/Errors/KernelReadError.cs @@ -10,7 +10,7 @@ // ----------------------------------------------------------------------------- using System; -using System.Runtime.InteropServices; +using DeltaLake.Extensions; using DeltaLake.Kernel.Interop; namespace DeltaLake.Kernel.Callbacks.Errors @@ -26,8 +26,8 @@ internal struct KernelReadError #pragma warning disable CS8603, IDE0251 // Possible pointer null reference return is possible when we work with Kernel if the Kernel has a bug public string Message { - get => Marshal.PtrToStringUTF8(msg); - set => msg = Marshal.StringToCoTaskMemUTF8(value); + get => MarshalExtensions.PtrToStringUTF8(msg); + set => msg = MarshalExtensions.StringToCoTaskMemUTF8(value); } #pragma warning restore CS8603, IDE0251 } diff --git a/src/DeltaLake/Kernel/Core/Table.cs b/src/DeltaLake/Kernel/Core/Table.cs index bcb15f18..7871f217 100644 --- a/src/DeltaLake/Kernel/Core/Table.cs +++ b/src/DeltaLake/Kernel/Core/Table.cs @@ -253,7 +253,7 @@ internal override string Uri() // Kernel returns an extra "/", delta-rs does not // - return Marshal.PtrToStringUTF8(tableRootPtr)?.TrimEnd('/') ?? string.Empty; + return MarshalExtensions.PtrToStringUTF8(tableRootPtr)?.TrimEnd('/') ?? string.Empty; } finally { @@ -347,7 +347,7 @@ private List PartitionColumns() for (int i = 0; i < numPartitions; i++) { partitionColumns.Add( - Marshal.PtrToStringUTF8((IntPtr)managedPartitionListPtr->Cols[i]) + MarshalExtensions.PtrToStringUTF8((IntPtr)managedPartitionListPtr->Cols[i]) ?? throw new InvalidOperationException( $"Delta Kernel returned a null partition column name despite reporting {numPartitions} > 0 partition(s) exist." ) diff --git a/src/DeltaLake/Kernel/Interop/Interop.cs b/src/DeltaLake/Kernel/Interop/Interop.cs index d0e2e3ef..23aa21ea 100644 --- a/src/DeltaLake/Kernel/Interop/Interop.cs +++ b/src/DeltaLake/Kernel/Interop/Interop.cs @@ -381,7 +381,17 @@ internal unsafe partial struct _Anonymous_e__Union internal partial struct _Anonymous1_e__Struct { +#if NETCOREAPP public bool ok; +#else + // Desktop framework apparently doesn't consider bool to be blittable + private int intOk; + + public bool ok + { + get => intOk != 0; + } +#endif } internal unsafe partial struct _Anonymous2_e__Struct diff --git a/src/DeltaLake/Table/TableMetadata.cs b/src/DeltaLake/Table/TableMetadata.cs index b807354f..ff6842bc 100644 --- a/src/DeltaLake/Table/TableMetadata.cs +++ b/src/DeltaLake/Table/TableMetadata.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.InteropServices; +using DeltaLake.Extensions; namespace DeltaLake.Table { @@ -64,11 +64,11 @@ internal unsafe static TableMetadata FromUnmanaged(Bridge.Interop.TableMetadata* var partitionColumns = StringArrayFromPointer(metadata->partition_columns, (int)metadata->partition_columns_count); return new DeltaLake.Table.TableMetadata { - Id = Marshal.PtrToStringUTF8(new IntPtr(metadata->id)) ?? string.Empty, - Name = Marshal.PtrToStringUTF8(new IntPtr(metadata->name)), - Description = Marshal.PtrToStringUTF8(new IntPtr(metadata->description)), - FormatProvider = Marshal.PtrToStringUTF8(new IntPtr(metadata->format_provider)) ?? string.Empty, - SchemaString = Marshal.PtrToStringUTF8(new IntPtr(metadata->schema_string)) ?? string.Empty, + Id = MarshalExtensions.PtrToStringUTF8(new IntPtr(metadata->id)) ?? string.Empty, + Name = MarshalExtensions.PtrToStringUTF8(new IntPtr(metadata->name)), + Description = MarshalExtensions.PtrToStringUTF8(new IntPtr(metadata->description)), + FormatProvider = MarshalExtensions.PtrToStringUTF8(new IntPtr(metadata->format_provider)) ?? string.Empty, + SchemaString = MarshalExtensions.PtrToStringUTF8(new IntPtr(metadata->schema_string)) ?? string.Empty, CreatedTime = DateTimeOffset.FromUnixTimeMilliseconds(metadata->created_time), FormatOptions = KeyValueToDictionaryNullable(metadata->format_options), PartitionColumns = partitionColumns, @@ -87,7 +87,7 @@ private unsafe static string[] StringArrayFromPointer(sbyte** pointer, int lengt for (var i = 0; i < length; i++) { var entry = *(pointer + i); - result[i] = Marshal.PtrToStringUTF8(new IntPtr(entry)) ?? string.Empty; + result[i] = MarshalExtensions.PtrToStringUTF8(new IntPtr(entry)) ?? string.Empty; } return result; diff --git a/tests/DeltaLake.Tests/DeltaLake.Tests.csproj b/tests/DeltaLake.Tests/DeltaLake.Tests.csproj index 1f42309b..604d7516 100644 --- a/tests/DeltaLake.Tests/DeltaLake.Tests.csproj +++ b/tests/DeltaLake.Tests/DeltaLake.Tests.csproj @@ -1,9 +1,12 @@ - + - net8.0 + net472;net8.0 + net8.0 true enable false + 12.0 + enable diff --git a/tests/DeltaLake.Tests/DirectoryHelpers.cs b/tests/DeltaLake.Tests/DirectoryHelpers.cs new file mode 100644 index 00000000..55092369 --- /dev/null +++ b/tests/DeltaLake.Tests/DirectoryHelpers.cs @@ -0,0 +1,15 @@ +namespace DeltaLake.Tests; + +internal static class DirectoryHelpers +{ + public static DirectoryInfo CreateTempSubdirectory() + { +#if NETCOREAPP + return Directory.CreateTempSubdirectory(); +#else + var tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(tempPath); + return new DirectoryInfo(tempPath); +#endif + } +} diff --git a/tests/DeltaLake.Tests/Settings.cs b/tests/DeltaLake.Tests/Settings.cs index 3625c93c..d101d421 100644 --- a/tests/DeltaLake.Tests/Settings.cs +++ b/tests/DeltaLake.Tests/Settings.cs @@ -2,6 +2,6 @@ namespace DeltaLake.Tests { public static class Settings { - public static string TestRoot = System.Environment.GetEnvironmentVariable("TEST_ROOT") ?? Path.Join("..", "..", "..", "..", "data"); + public static string TestRoot = System.Environment.GetEnvironmentVariable("TEST_ROOT") ?? Path.Combine("..", "..", "..", "..", "data"); } } \ No newline at end of file diff --git a/tests/DeltaLake.Tests/Table/DeleteTests.cs b/tests/DeltaLake.Tests/Table/DeleteTests.cs index 362c14a8..635bbee4 100644 --- a/tests/DeltaLake.Tests/Table/DeleteTests.cs +++ b/tests/DeltaLake.Tests/Table/DeleteTests.cs @@ -57,7 +57,7 @@ public async Task File_System_Insert_Variable_Record_Delete_Test( string? predicate, int expectedRecords) { - var info = Directory.CreateTempSubdirectory(); + var info = DirectoryHelpers.CreateTempSubdirectory(); try { await BaseDeleteTest($"file://{info.FullName}", length, predicate, expectedRecords); diff --git a/tests/DeltaLake.Tests/Table/InsertTests.cs b/tests/DeltaLake.Tests/Table/InsertTests.cs index 7b0e9169..43d2d284 100644 --- a/tests/DeltaLake.Tests/Table/InsertTests.cs +++ b/tests/DeltaLake.Tests/Table/InsertTests.cs @@ -21,7 +21,7 @@ public async Task Memory_Insert_Variable_Record_Count_Test(int length) [InlineData(100)] public async Task File_System_Insert_Variable_Record_Count_Test(int length) { - var info = Directory.CreateTempSubdirectory(); + var info = DirectoryHelpers.CreateTempSubdirectory(); try { await BaseInsertTest($"file://{info.FullName}", length); diff --git a/tests/DeltaLake.Tests/Table/KernelTests.cs b/tests/DeltaLake.Tests/Table/KernelTests.cs index 3bfda4df..a0ef99a8 100644 --- a/tests/DeltaLake.Tests/Table/KernelTests.cs +++ b/tests/DeltaLake.Tests/Table/KernelTests.cs @@ -60,7 +60,7 @@ public async Task Multi_Partitioned_Table_Parallelized_Bridge_Write_Can_Be_Read_ int numRows = numRowsPerPartition * numConcurrentWriters; - var tempDir = Directory.CreateTempSubdirectory(); + var tempDir = DirectoryHelpers.CreateTempSubdirectory(); using IEngine engine = new DeltaEngine(EngineOptions.Default); var builder = new Apache.Arrow.Schema.Builder() .Field(fb => { fb.Name(stringColumnName); fb.DataType(StringType.Default); fb.Nullable(false); }) diff --git a/tests/DeltaLake.Tests/Table/TableHelpers.cs b/tests/DeltaLake.Tests/Table/TableHelpers.cs index 1f65a3f5..ca6037f0 100644 --- a/tests/DeltaLake.Tests/Table/TableHelpers.cs +++ b/tests/DeltaLake.Tests/Table/TableHelpers.cs @@ -62,7 +62,7 @@ public static class TableHelpers [TableIdentifier.Delta121OnlyStructStats] = "delta-1.2.1-only-struct-stats", [TableIdentifier.Delta220PartitionedTypes] = "delta-2.2.0-partitioned-types", [TableIdentifier.DeltaLiveTable] = "delta-live-table", - [TableIdentifier.Golden] = Path.Join("golden", "data-reader-array-primitives"), + [TableIdentifier.Golden] = Path.Combine("golden", "data-reader-array-primitives"), [TableIdentifier.HttpRequests] = "http_requests", [TableIdentifier.Issue1374] = "issue_1374", [TableIdentifier.SimpleCommit] = "simple_commit", @@ -88,12 +88,12 @@ public static class TableHelpers public static string LogPath(this TableIdentifier tid, string? pathRoot = null) { - return Path.Join(pathRoot ?? Settings.TestRoot, Tables[tid], "_delta_log"); + return Path.Combine(pathRoot ?? Settings.TestRoot, Tables[tid], "_delta_log"); } public static string TablePath(this TableIdentifier tid, string? pathRoot = null) { - return Path.Join(pathRoot ?? Settings.TestRoot, Tables[tid]); + return Path.Combine(pathRoot ?? Settings.TestRoot, Tables[tid]); } public static Task<(IEngine engine, ITable table)> SetupTable(string path, int length) diff --git a/tests/DeltaLake.Tests/Table/TableTests.cs b/tests/DeltaLake.Tests/Table/TableTests.cs index 82f5e5e7..f156bb82 100644 --- a/tests/DeltaLake.Tests/Table/TableTests.cs +++ b/tests/DeltaLake.Tests/Table/TableTests.cs @@ -124,7 +124,7 @@ public async Task Create_InMemory_With_Partitions_Test() [Fact] public async Task Load_Table_Test() { - var location = Path.Join(Settings.TestRoot, "simple_table"); + var location = Path.Combine(Settings.TestRoot, "simple_table"); using IEngine engine = new DeltaEngine(EngineOptions.Default); using var table = await engine.LoadTableAsync(new TableOptions() { TableLocation = location }, CancellationToken.None); Assert.Equal(4UL, table.Version()); @@ -135,7 +135,7 @@ public async Task Load_Cancellation_Test() { await Assert.ThrowsAnyAsync(async () => { - var location = Path.Join(Settings.TestRoot, "simple_table"); + var location = Path.Combine(Settings.TestRoot, "simple_table"); using IEngine engine = new DeltaEngine(EngineOptions.Default); using var table = await engine.LoadTableAsync(new TableOptions() { TableLocation = location }, new CancellationToken(true)); Assert.Equal(4UL, table.Version());