Skip to content

feat: Add typed WithResourceMapping(...) overloads#1497

Merged
HofmeisterAn merged 11 commits intotestcontainers:developfrom
cimnine:WithResourceMapping
Mar 3, 2026
Merged

feat: Add typed WithResourceMapping(...) overloads#1497
HofmeisterAn merged 11 commits intotestcontainers:developfrom
cimnine:WithResourceMapping

Conversation

@cimnine
Copy link
Copy Markdown
Contributor

@cimnine cimnine commented Jul 30, 2025

What does this PR do?

Overhaul of WithResourceMapping().
The methods with string arguments are deprecated and replaced with the following methods. These signatures are explicit with regard to the target path being a file or directory path.

WithResourceMapping(FileInfo, DirectoryInfo, UnixFileModes fileMode = Unix.FileMode644);
WithResourceMapping(FileInfo, FileInfo, UnixFileModes fileMode = Unix.FileMode644);
WithResourceMapping(DirectoryInfo, DirectoryInfo, UnixFileModes fileMode = Unix.FileMode644);
WithResourceMapping(byte[], FileInfo, UnixFileModes fileMode = Unix.FileMode644);
WithResourceMapping(Uri, FileInfo, UnixFileModes fileMode = Unix.FileMode644);
WithResourceMapping(Uri, DirectoryInfo, UnixFileModes fileMode = Unix.FileMode644);

Why is it important?

With the previous API, it wasn't consistent whether the target string path is a directory or a file.

Related issues

Summary by CodeRabbit

  • New Features

    • Strongly-typed FilePath and DirectoryPath APIs and string-to-path helpers.
    • Expanded resource-mapping: many additional source/target combinations, URI sources, and byte-array content support.
  • Deprecated

    • Legacy string/FileInfo/DirectoryInfo-based resource-mapping overloads marked obsolete; use typed alternatives.
  • Refactor

    • Resource-mapping overloads standardized and routed through consolidated implementations for consistency.
  • Tests

    • Coverage extended for broader file/directory/URI mapping scenarios.
  • Documentation

    • Examples updated to use the new typed path APIs.

@netlify
Copy link
Copy Markdown

netlify bot commented Jul 30, 2025

Deploy Preview for testcontainers-dotnet ready!

Name Link
🔨 Latest commit 069674d
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-dotnet/deploys/69a6c9299699da0008885bc8
😎 Deploy Preview https://deploy-preview-1497--testcontainers-dotnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Collaborator

@HofmeisterAn HofmeisterAn left a comment

Choose a reason for hiding this comment

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

Thanks for taking care of this! Could you please remove/revert the unnecessary changes (like extra whitespace, line breaks, etc.)? That would make the review much easier 🙏.

@cimnine cimnine force-pushed the WithResourceMapping branch from 8e1a8dc to 0dbb5a1 Compare July 31, 2025 15:23
@cimnine cimnine force-pushed the WithResourceMapping branch from 0dbb5a1 to 3399e09 Compare July 31, 2025 15:25
@cimnine
Copy link
Copy Markdown
Contributor Author

cimnine commented Jul 31, 2025

Could you please remove/revert the unnecessary changes

Sure, sorry for that. I also rebased while at it.

@HofmeisterAn HofmeisterAn added the enhancement New feature or request label Aug 2, 2025
Copy link
Copy Markdown
Collaborator

@HofmeisterAn HofmeisterAn left a comment

Choose a reason for hiding this comment

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

Thanks for the PR 🙏.

After taking a closer look at the PR, I remembered why we didn't introduce this earlier.
The issue with FileSystemInfo implementations (DirectoryInfo, FileInfo) is that they obviously refer to the underlying OS.

On Windows, some of the tests fail because files can't be copied into the container properly.
For example, using new FileInfo("/test.txt") ends up referring to C:\test.txt, which isn't what we want (as target).

We need an abstraction that works with the target container OS as well, unfortunately.

@cimnine
Copy link
Copy Markdown
Contributor Author

cimnine commented Aug 31, 2025

On Windows, some of the tests fail because files can't be copied into the container properly.
For example, using new FileInfo("/test.txt") ends up referring to C:\test.txt, which isn't what we want (as target).

Pity. What about providing our own abstraction for File- vs. Directory-Paths? Basically a Record containing a single String. I imagine two classes with each a static helper like FilePath.of("/blabla/file") and DirPath.of("/jiiihaaa/dir"). And/or an extension method for String like "/path/to/file".AsFile() and "/path/to/dir".AsDir() (comparable to the approach Flurl takes).

@HofmeisterAn
Copy link
Copy Markdown
Collaborator

Sounds like a good idea 👍. We probably just need something like this (and the equivalent for directory):

public readonly record struct FilePath
{
    private FilePath(string value)
    {
        Value = Unix.Instance.NormalizePath(value); // This method already exists in Testcontainers.
    }

    public string Value { get; }

    public static FilePath Of(string path) => new FilePath(path);
}

WDYT?

@HofmeisterAn HofmeisterAn force-pushed the develop branch 3 times, most recently from 4900ecd to 8fa5f1b Compare October 3, 2025 20:17
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 1, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds strongly-typed path wrappers (FilePath, DirectoryPath) and path helpers, expands WithResourceMapping with many new overloads (FilePath/DirectoryPath/FileInfo/DirectoryInfo/Uri/byte[] permutations), updates tests and docs to use them, and standardizes ThrowIf lambdas to return exception instances.

Changes

Cohort / File(s) Summary
Path types & helpers
src/Testcontainers/Builders/FilePath.cs, src/Testcontainers/Builders/DirectoryPath.cs, src/Testcontainers/Builders/PathExtensions.cs
Adds FilePath and DirectoryPath readonly record structs with validation and Unix path normalization; adds string extension helpers AsFile() / AsDirectory().
Container builder overloads
src/Testcontainers/Builders/ContainerBuilder\3.cs, src/Testcontainers/Builders/IContainerBuilder`2.cs`
Introduces many new WithResourceMapping overloads for combinations of FilePath/DirectoryPath/FileInfo/DirectoryInfo/Uri/byte[]; funnels legacy overloads through new routes and marks several string-based/ambiguous variants Obsolete.
Tests
tests/Testcontainers.Platform.Linux.Tests/TarOutputMemoryStreamTest.cs
Expands test cases and target file/directory paths to cover new FilePath/DirectoryPath and Uri/byte[] resource-mapping permutations.
Docs & examples
docs/api/create_docker_container.md
Updates examples to use FilePath.Of(...) / DirectoryPath.Of(...) and reflects new WithResourceMapping signatures.
Validation / ThrowIf changes
src/Testcontainers.EventHubs/EventHubsBuilder.cs, src/Testcontainers.Neo4j/Neo4jBuilder.cs, src/Testcontainers.Oracle/OracleBuilder.cs, src/Testcontainers/Configurations/WaitStrategies/WaitStrategy.cs
Refactors ThrowIf callbacks to return constructed exception instances (e.g., new ArgumentException(...) / new RetryLimitExceededException(...)) instead of throwing directly inside the lambda.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped through paths both new and bright,
FilePath and DirectoryPath in my sight.
Mappings multiplied, routes tidy and sure,
Old strings bowed out, strong types endure.
A happy hop — code stamped with a carrot's bite! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Add typed WithResourceMapping(...) overloads' accurately reflects the main change: introducing new explicit, strongly-typed overloads for WithResourceMapping methods.
Description check ✅ Passed The description explains what the PR does, why it's important, and links to issue #1486. However, it lacks testing instructions and follow-ups as suggested by the template.
Linked Issues check ✅ Passed The PR addresses issue #1486 by introducing explicit FilePath/DirectoryPath types to disambiguate file vs. directory targets in WithResourceMapping, directly resolving the bug where files were created as directories.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the WithResourceMapping overhaul and supporting infrastructure (FilePath, DirectoryPath types, path extensions, documentation updates, and exception handling refactoring in ThrowIf calls).
Docstring Coverage ✅ Passed Docstring coverage is 90.57% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/Testcontainers/Builders/IContainerBuilder`2.cs (1)

438-458: Minor documentation inconsistency in remarks.

The remarks on lines 448-449 reference WithResourceMapping(Uri, FilePath, ...) as the method for copying a file to a specific target file path. However, for file-to-file mappings, WithResourceMapping(FileInfo, FileInfo, ...) or WithResourceMapping(FilePath, FilePath, ...) would be more appropriate references since this overload already accepts a DirectoryPath target.

📝 Suggested documentation fix
     /// If you prefer to copy a file to a specific target file path instead of a
-    /// directory, use: <see cref="WithResourceMapping(Uri, FilePath, uint, uint, UnixFileModes)" />.
+    /// directory, use: <see cref="WithResourceMapping(FilePath, FilePath, uint, uint, UnixFileModes)" />.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Testcontainers/Builders/IContainerBuilder``2.cs around lines 438 - 458,
The XML remarks wrongly suggest the file-to-file overload as
WithResourceMapping(Uri, FilePath, ...) while this overload accepts a
DirectoryPath target; update the remark to reference the correct file-to-file
overloads such as WithResourceMapping(FilePath, FilePath, ...) and/or
WithResourceMapping(FileInfo, FileInfo, ...) (or add both) so callers understand
which methods to use when copying to a specific target file path; keep the
existing DirectoryPath explanation for the current WithResourceMapping(Uri,
DirectoryPath, ...) signature.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Testcontainers/Builders/ContainerBuilder``3.cs:
- Around line 272-276: The WithResourceMapping(FileInfo source, DirectoryInfo
target, uint uid = 0, uint gid = 0, UnixFileModes fileMode = Unix.FileMode644)
overload in class ContainerBuilder`3 is using target.ToString() when creating
the DirectoryPath; change it to use target.FullName so the path is the actual
filesystem path (i.e., call DirectoryPath.Of(target.FullName)) to match the
FileInfo usage and ensure correct path resolution.
- Around line 309-313: In WithResourceMapping(Uri source, DirectoryInfo target,
uint uid = 0, uint gid = 0, UnixFileModes fileMode = Unix.FileMode644) in
ContainerBuilder`3, replace target.ToString() with target.FullName when creating
the DirectoryPath (i.e., call DirectoryPath.Of(target.FullName)) to ensure the
absolute filesystem path is used instead of the DirectoryInfo's ToString()
representation.
- Around line 254-258: Multiple overloads in ContainerBuilder`3 are using
target.ToString() (e.g., in WithResourceMapping and other mapping methods) which
can return a non-absolute path; replace those calls with target.FullName so
DirectoryPath.Of(...) and FilePath.Of(...) receive absolute paths. Update the
occurrences cited: change DirectoryPath.Of(target.ToString()) to
DirectoryPath.Of(target.FullName) and FilePath.Of(target.ToString()) to
FilePath.Of(target.FullName) in the WithResourceMapping(DirectoryInfo, ...), the
other DirectoryInfo overload(s) and the FileInfo overload(s) so all path
resolution uses FullName.

---

Nitpick comments:
In `@src/Testcontainers/Builders/IContainerBuilder``2.cs:
- Around line 438-458: The XML remarks wrongly suggest the file-to-file overload
as WithResourceMapping(Uri, FilePath, ...) while this overload accepts a
DirectoryPath target; update the remark to reference the correct file-to-file
overloads such as WithResourceMapping(FilePath, FilePath, ...) and/or
WithResourceMapping(FileInfo, FileInfo, ...) (or add both) so callers understand
which methods to use when copying to a specific target file path; keep the
existing DirectoryPath explanation for the current WithResourceMapping(Uri,
DirectoryPath, ...) signature.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8482b5 and 16f3e00.

📒 Files selected for processing (7)
  • src/Testcontainers/Builders/ContainerBuilder3.cs`
  • src/Testcontainers/Builders/DirectoryPath.cs
  • src/Testcontainers/Builders/FilePath.cs
  • src/Testcontainers/Builders/IContainerBuilder2.cs`
  • src/Testcontainers/Builders/PathExtensions.cs
  • tests/Testcontainers.Platform.Linux.Tests/TarOutputMemoryStreamTest.cs
  • tests/Testcontainers.Tests/Fixtures/Configurations/AlpineBuilderFixture.cs

@HofmeisterAn HofmeisterAn changed the title Clean up WithResourceMapping feat: Add typed WithResourceMapping(...) overloads Mar 2, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/Testcontainers/Builders/IContainerBuilder`2.cs (1)

332-367: Minor documentation inconsistency in XML comments.

The summary for lines 332-333 says "Copies a test host directory or file" but the method signature (FileInfo source / FilePath source) clearly indicates it's for file sources only. Consider updating to "Copies a test host file to the given directory".

📝 Suggested documentation fix
     /// <summary>
-    /// Copies a test host directory or file to the given directory in the container before it starts.
+    /// Copies a test host file to the given directory in the container before it starts.
     /// </summary>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Testcontainers/Builders/IContainerBuilder``2.cs around lines 332 - 367,
Update the XML <summary> for the WithResourceMapping overloads to accurately
reflect that the source is a file (not "directory or file"): change the summary
text for WithResourceMapping(FileInfo, string, ...),
WithResourceMapping(FileInfo, DirectoryInfo, ...), and
WithResourceMapping(FilePath, DirectoryPath, ...) from "Copies a test host
directory or file to the given directory in the container before it starts." to
something like "Copies a test host file to the given directory in the container
before it starts." and ensure the parameter descriptions remain consistent with
the file-source signatures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Testcontainers/Builders/ContainerBuilder``3.cs:
- Around line 278-282: The FilePath->DirectoryPath overload
(WithResourceMapping(FilePath source, DirectoryPath target, ...)) currently
passes the target directory as the containerPath, causing incorrect mappings;
change it to extract the filename from source (e.g., via
Path.GetFileName(source.Value) or source.FileName) and combine that filename
with the target directory to produce a full container file path before
constructing FileResourceMapping, mirroring the behavior in the
Uri->DirectoryPath overload (WithResourceMapping(Uri, DirectoryPath, ...)); also
ensure the FileInfo->DirectoryInfo overload that delegates to the FilePath
overload continues to work correctly after this change.

---

Nitpick comments:
In `@src/Testcontainers/Builders/IContainerBuilder``2.cs:
- Around line 332-367: Update the XML <summary> for the WithResourceMapping
overloads to accurately reflect that the source is a file (not "directory or
file"): change the summary text for WithResourceMapping(FileInfo, string, ...),
WithResourceMapping(FileInfo, DirectoryInfo, ...), and
WithResourceMapping(FilePath, DirectoryPath, ...) from "Copies a test host
directory or file to the given directory in the container before it starts." to
something like "Copies a test host file to the given directory in the container
before it starts." and ensure the parameter descriptions remain consistent with
the file-source signatures.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16f3e00 and fd48aaa.

📒 Files selected for processing (2)
  • src/Testcontainers/Builders/ContainerBuilder3.cs`
  • src/Testcontainers/Builders/IContainerBuilder2.cs`

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/api/create_docker_container.md (1)

63-63: Add an explicit deprecation/migration note for string-based overloads.

This section introduces typed paths well, but a short note here that WithResourceMapping(string, string) is deprecated would reduce ambiguity during migration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/api/create_docker_container.md` at line 63, Add a short explicit
deprecation/migration note after the paragraph introducing FilePath and
DirectoryPath that states the old string-based overload
WithResourceMapping(string, string) is deprecated; instruct consumers to switch
to the strongly-typed overloads WithResourceMapping(FilePath, DirectoryPath) (or
the corresponding FilePath/FilePath variants) and briefly mention any behavioral
or validation differences to be aware of during migration (e.g., path
normalization/validation).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/api/create_docker_container.md`:
- Line 82: The example uses Encoding.Default which is platform-dependent; update
the .WithResourceMapping call to use Encoding.UTF8 for the byte array so the
docs/tests produce consistent output across environments (i.e., replace
Encoding.Default.GetBytes("{}") with Encoding.UTF8.GetBytes("{}") in the
.WithResourceMapping(FilePath.Of("/app/appsettings.json")) example).

---

Nitpick comments:
In `@docs/api/create_docker_container.md`:
- Line 63: Add a short explicit deprecation/migration note after the paragraph
introducing FilePath and DirectoryPath that states the old string-based overload
WithResourceMapping(string, string) is deprecated; instruct consumers to switch
to the strongly-typed overloads WithResourceMapping(FilePath, DirectoryPath) (or
the corresponding FilePath/FilePath variants) and briefly mention any behavioral
or validation differences to be aware of during migration (e.g., path
normalization/validation).

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1279357 and 65a86bb.

📒 Files selected for processing (1)
  • docs/api/create_docker_container.md

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/api/create_docker_container.md`:
- Around line 115-121: The doc example title mismatches the snippet: the heading
says "Copying a file with specific UID and GID" but the code uses
DirectoryPath.Of(...) and ContainerBuilder.WithResourceMapping to copy a
directory; either update the heading to "Copying a directory with specific UID
and GID" or change the snippet to use FilePath.Of(...) (and adjust the
destination to a file path) so the example and title match; reference
ContainerBuilder, WithResourceMapping, DirectoryPath.Of and FilePath.Of when
making the edit.
- Around line 128-133: The heading "Copying a script with executable
permissions" doesn't match the snippet which uses DirectoryPath.Of and maps a
directory via ContainerBuilder.WithResourceMapping; update the example title to
"Copying a directory with executable permissions" to match the code (references:
ContainerBuilder, WithResourceMapping, DirectoryPath.Of, Unix.FileMode755) so
the doc accurately describes the shown directory mapping.

In `@src/Testcontainers/Builders/IContainerBuilder``2.cs:
- Around line 448-552: The XML docs for the typed Uri overloads are
contradictory: update the comments for WithResourceMapping(Uri, DirectoryInfo),
WithResourceMapping(Uri, DirectoryPath) to clearly state these overloads always
copy the source into the specified target directory (filename is derived from
the source and directory structure is not preserved) and remove the ambiguous
"if scheme is file/http/https" wording that implies different behaviors;
likewise update WithResourceMapping(Uri, FileInfo) and WithResourceMapping(Uri,
FilePath) to state they always copy to the specified target file path and accept
http/https/file sources, ensuring summary/remarks match the concrete intent
encoded by the method signatures and adjust or remove misleading examples in
those overloads.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65a86bb and 93282f1.

📒 Files selected for processing (3)
  • docs/api/create_docker_container.md
  • src/Testcontainers/Builders/IContainerBuilder2.cs`
  • tests/Testcontainers.Platform.Linux.Tests/TarOutputMemoryStreamTest.cs

@HofmeisterAn HofmeisterAn merged commit 934e972 into testcontainers:develop Mar 3, 2026
80 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Copy a file WithResourceMapping leads to an (empty) directory in the container

2 participants