Skip to content

fix: file stream sharing#1363

Merged
vbreuss merged 23 commits into
TestableIO:mainfrom
HarrisonTCodes:fix/file-stream-sharing
Nov 21, 2025
Merged

fix: file stream sharing#1363
vbreuss merged 23 commits into
TestableIO:mainfrom
HarrisonTCodes:fix/file-stream-sharing

Conversation

@HarrisonTCodes

@HarrisonTCodes HarrisonTCodes commented Oct 30, 2025

Copy link
Copy Markdown
Contributor

Closes #1356

This PR adds stateful handling of file streams opened with the FileShare.None option. If a file stream is attempted to be opened whilst another file stream of the same file path and FileShare.None is in use (that is to say, has been opened and not yet disposed), an IOException will be thrown and the creation of the second file stream will be disallowed.

@HarrisonTCodes

Copy link
Copy Markdown
Contributor Author

Struggling to initially parse these API tests, not least because I can't seem to reproduce exactly on my machine. However, I expect the cause of failure might be because of the addition of the share argument in the MockFileStream constructor in MockFileStream.cs.

If this is the case, presumably this could be fixed by having share be the final argument (and keeping its default value), so the old argument order, including omission of this new one, would still be valid? This may not be ideal or align with the real file stream implementation though?

Worth nothing none of the factory methods have had their arguments or argument order changed.

@vbreuss

vbreuss commented Oct 31, 2025

Copy link
Copy Markdown
Member

Struggling to initially parse these API tests, not least because I can't seem to reproduce exactly on my machine. However, I expect the cause of failure might be because of the addition of the share argument in the MockFileStream constructor in MockFileStream.cs.

If this is the case, presumably this could be fixed by having share be the final argument (and keeping its default value), so the old argument order, including omission of this new one, would still be valid? This may not be ideal or align with the real file stream implementation though?

Worth nothing none of the factory methods have had their arguments or argument order changed.

@HarrisonTCodes : You change the public API surface in this PR. The API tests fail, because you didn't make this explicit in the PR. In order for the tests to succeed, you have to run the TestableIO.System.IO.Abstractions.Api.Tests.ApiAcceptance.AcceptApiChanges test once. This will adapt the API files and you have to commit them as part of this PR:
image

This way accidental API changes can be detected in the review.

Note, that this test is explicit!

@vbreuss vbreuss left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you please add test cases to verify the correct behavior?

@HarrisonTCodes

Copy link
Copy Markdown
Contributor Author

Ah, thanks @vbreuss, sorry I missed that. I will try to run these explicit tests locally!

Yes, if we are happy with the structure and changes made in this PR (which seems to be the case based on this request), I shall consider them accepted and add test cases :)

@hangy hangy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I like the idea!

It might be useful to check if symbolic links need additional handling

Comment thread src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStream.cs Outdated
@HarrisonTCodes

Copy link
Copy Markdown
Contributor Author

I like the idea!

It might be useful to check if symbolic links need additional handling

@hangy thanks for raising this :)

Maybe this is worth more discussion, and a clarification of the scope of this PR. Currently it just targets the behavior shown in the original (linked) issue, ie creation of a MockFileStream with an explicit FileShare.None argument. This seems like handy behavior to have when explicitly passing this argument.

However, there might be appetite to improve the handling of FileShare behavior across more of the APIs, such as in MockFile.cs and implicit file-sharing that mimics the real filesystem with methods like FileInfo.OpenWrite() too.

More realistic handling of other FileShare members might also be worth thinking about in the future too for example. This PR currently just handles FileShare.None. But maybe there is scope to handle these other modes better, such as disallowing write operations on a file when a file stream is open with just FileShare.Read (which could be doable with the use of a ConcurrentDictionary now instead of the old HashSet, with the value representing the share type!)

Comment thread src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStreamFactory.cs Outdated
Comment thread src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStream.cs Outdated
Comment thread src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStream.cs Outdated

@vbreuss vbreuss left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I really like this change. I would just make some things internal to enable future refactorings without breaking changes...

Comment thread src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileSystem.cs Outdated
Comment thread src/TestableIO.System.IO.Abstractions.TestingHelpers/PathVerifier.cs Outdated
microsoft-github-policy-service Bot pushed a commit to Azure/bicep that referenced this pull request Jun 8, 2026
#19832)

Updated
[TestableIO.System.IO.Abstractions.Wrappers](https://github.com/TestableIO/System.IO.Abstractions)
from 22.0.15 to 22.1.1.

<details>
<summary>Release notes</summary>

_Sourced from [TestableIO.System.IO.Abstractions.Wrappers's
releases](https://github.com/TestableIO/System.IO.Abstractions/releases)._

## 22.1.1

## What's Changed
* chore(deps): update dependency githubactionstestlogger to v3 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1380
* chore(deps): update dependency githubactionstestlogger to 3.0.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1381
* chore(deps): update dependency publicapigenerator to 11.5.2 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1382
* chore(deps): update dependency publicapigenerator to 11.5.3 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1383
* chore(deps): update dependency sharpcompress to 0.42.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1384
* chore(deps): update dependency benchmarkdotnet to 0.15.8 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1385
* chore(deps): update dependency publicapigenerator to 11.5.4 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1387
* chore(deps): update dependency nunit3testadapter to v6 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1388
* chore(deps): update dependency sharpcompress to 0.42.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1389
* chore(deps): update dependency system.text.json to 10.0.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1390
* chore(deps): update dependency dotnet-sdk to v10.0.101 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1391
* chore(deps): update github artifact actions (major) by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1392
* chore(deps): update dependency nunit3testadapter to 6.0.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1393
* chore(deps): update dependency sharpcompress to 0.43.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1394
* chore(deps): update dependency nunit3testadapter to 6.1.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1395
* chore(deps): update dependency sharpcompress to 0.44.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1396
* chore(deps): update dependency system.text.json to 10.0.2 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1397
* chore(deps): update dependency dotnet-sdk to v10.0.102 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1398
* chore(deps): update dependency awexpect to 2.30.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1399
* chore(deps): update dependency sharpcompress to 0.44.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1400
* chore(deps): update apexskier/github-release-commenter action to
v1.4.1 by @​renovate[bot] in
TestableIO/System.IO.Abstractions#1401
* chore(deps): update dependency sharpcompress to 0.44.2 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1403
* chore: bump nuke to v10.1 by @​vbreuss in
TestableIO/System.IO.Abstractions#1404
* refactor: replace Moq with Mockolate by @​vbreuss in
TestableIO/System.IO.Abstractions#1405
* refactor: migrate to slnx format by @​vbreuss in
TestableIO/System.IO.Abstractions#1406
* fix: pin `System.Text.Json` versions for older frameworks by @​vbreuss
in TestableIO/System.IO.Abstractions#1407
* refactor: remove explicit .NET6 tests by @​vbreuss in
TestableIO/System.IO.Abstractions#1408
* chore: bump Mockolate to v1.0.1 by @​vbreuss in
TestableIO/System.IO.Abstractions#1410
* chore(deps): update dependency mockolate to 1.0.2 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1411
* chore: bump Mockolate to v1.0.3 by @​vbreuss in
TestableIO/System.IO.Abstractions#1412
* chore(deps): update dependency sharpcompress to 0.44.3 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1414
* chore(deps): update dependency sharpcompress to 0.44.4 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1415
* chore(deps): update dependency sharpcompress to 0.44.5 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1416
* chore(deps): update dependency mockolate to 1.0.4 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1417
* chore(deps): update dependency mockolate to 1.1.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1418
* chore(deps): update dependency mockolate to 1.2.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1419
* chore(deps): update dependency mockolate to 1.3.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1420
* chore(deps): update dependency mockolate to 1.4.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1421
* chore(deps): update dependency system.text.json to 10.0.3 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1422
* chore: bump Mockolate to v1.4.1 by @​vbreuss in
TestableIO/System.IO.Abstractions#1423
* chore(deps): update dependency sharpcompress to 0.45.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1425
* chore(deps): update dependency sharpcompress to 0.45.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1426
* chore(deps): update dependency dotnet-sdk to v10.0.103 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1427
* chore(deps): update dependency sharpcompress to 0.46.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1428
* chore(deps): update dependency coverlet.collector to v8 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1429
* chore(deps): update dependency sharpcompress to 0.46.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1430
* chore(deps): update dependency sharpcompress to 0.46.2 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1431
* chore(deps): update dependency nunit to 4.5.0 by @​renovate[bot] in
TestableIO/System.IO.Abstractions#1432
* chore(deps): update dependency
testably.abstractions.filesystem.interface to 10.1.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1433
 ... (truncated)

## 22.1.0

## What's Changed
* chore(deps): update dependency awexpect to 2.24.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1341
* chore(deps): update dependency benchmarkdotnet to 0.15.3 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1342
* chore(deps): update dependency awexpect to 2.25.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1343
* chore(deps): update dependency benchmarkdotnet to 0.15.4 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1344
* chore(deps): update dependency awexpect to 2.26.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1345
* chore(deps): update dependency nunit3testadapter to 5.2.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1348
* docs: removed erroneous content from Testably section in README by
@​HarrisonTCodes in
TestableIO/System.IO.Abstractions#1349
* fix: make invalid UNC path error message platform-specific by
@​HarrisonTCodes in
TestableIO/System.IO.Abstractions#1351
* chore(deps): update dependency sharpcompress to 0.41.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1352
* chore(deps): update dependency publicapigenerator to 11.5.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1353
* chore(deps): update dependency system.text.json to 9.0.10 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1354
* chore(deps): update dependency dotnet-sdk to v9.0.306 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1355
* chore(deps): update mcr.microsoft.com/vscode/devcontainers/dotnet
docker tag to v10 by @​renovate[bot] in
TestableIO/System.IO.Abstractions#1357
* chore(deps): update github artifact actions (major) by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1359
* chore(deps): update dependency nunit.analyzers to 4.11.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1362
* chore(deps): update dependency benchmarkdotnet to 0.15.5 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1364
* chore(deps): update dependency nunit.analyzers to 4.11.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1365
* chore(deps): update dependency nunit.analyzers to 4.11.2 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1366
* chore(deps): update dependency benchmarkdotnet to 0.15.6 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1367
* chore(deps): update dependency system.text.json to v10 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1369
* chore(deps): update dependency dotnet-sdk to v9.0.307 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1368
* chore(deps): update dependency
testably.abstractions.filesystem.interface to v10 by @​renovate[bot] in
TestableIO/System.IO.Abstractions#1372
* feat: add support for .NET 10 by @​vbreuss in
TestableIO/System.IO.Abstractions#1370
* chore(deps): update dependency system.text.json to v10 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1373
* chore(deps): update dependency benchmarkdotnet to 0.15.7 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1374
* chore(deps): update dependency publicapigenerator to 11.5.1 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1375
* chore(deps): update actions/checkout action to v6 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1376
* fix: file stream sharing by @​HarrisonTCodes in
TestableIO/System.IO.Abstractions#1363
* chore(deps): update dependency awexpect to 2.29.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1358
* chore(deps): update dependency awexpect.testably to 0.13.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1360
* chore: bump aweXpect to v2.29.0 by @​vbreuss in
TestableIO/System.IO.Abstractions#1379

## New Contributors
* @​HarrisonTCodes made their first contribution in
TestableIO/System.IO.Abstractions#1349

**Full Changelog**:
TestableIO/System.IO.Abstractions@v22.0.16...v22.1.0

## 22.0.16

## What's Changed
* chore(deps): update dependency system.text.json to 9.0.7 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1306
* chore(deps): update dependency awexpect to 2.18.1 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1307
* chore(deps): update dependency dotnet-sdk to v9.0.302 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1308
* chore(deps): update dependency awexpect to 2.19.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1309
* chore(deps): update dependency awexpect to 2.19.1 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1310
* chore(deps): update dependency awexpect.testably to 0.11.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1311
* chore(deps): update dependency dotnet-sdk to v9.0.303 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1314
* chore(deps): update dependency awexpect to 2.20.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1315
* chore(deps): update dependency awexpect to 2.21.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1316
* chore(deps): update dependency system.text.json to 9.0.8 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1317
* chore(deps): update dependency dotnet-sdk to v9.0.304 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1318
* chore(deps): update actions/download-artifact action to v5 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1319
* chore(deps): update dependency nunit.analyzers to 4.10.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1320
* chore(deps): update dependency nunit to 4.4.0 by @​renovate[bot] in
TestableIO/System.IO.Abstractions#1321
* chore(deps): update dependency nunit3testadapter to 5.1.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1322
* chore(deps): update actions/checkout action to v5 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1323
* chore(deps): update dependency awexpect to 2.21.1 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1324
* docs: Add comprehensive documentation about relationship with
Testably.Abstractions by @​Copilot in
TestableIO/System.IO.Abstractions#1326
* docs: Create comprehensive GitHub Copilot instructions for
System.IO.Abstractions development by @​Copilot in
TestableIO/System.IO.Abstractions#1328
* chore(deps): update dependency awexpect to 2.22.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1331
* chore(deps): update actions/setup-dotnet action to v5 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1332
* chore(deps): update dependency awexpect to 2.23.0 by @​renovate[bot]
in TestableIO/System.IO.Abstractions#1334
* chore(deps): update dependency system.text.json to 9.0.9 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1333
* chore(deps): update dependency dotnet-sdk to v9.0.305 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1335
* chore(deps): update dependency awexpect.testably to 0.12.0 by
@​renovate[bot] in
TestableIO/System.IO.Abstractions#1336
* fix: Add TypeForwardedTo attribute to forward IFileSystem usage to its
new… by @​borisf94 in
TestableIO/System.IO.Abstractions#1338
* fix: use `dotnet nuget` to push packages by @​vbreuss in
TestableIO/System.IO.Abstractions#1339
* fix: Add TypeForwardedTo attribute to forward other moved interfaces
by @​borisf94 in
TestableIO/System.IO.Abstractions#1340

## New Contributors
* @​Copilot made their first contribution in
TestableIO/System.IO.Abstractions#1326
* @​borisf94 made their first contribution in
TestableIO/System.IO.Abstractions#1338

**Full Changelog**:
TestableIO/System.IO.Abstractions@v22.0.15...v22.0.16

Commits viewable in [compare
view](TestableIO/System.IO.Abstractions@v22.0.15...v22.1.1).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=TestableIO.System.IO.Abstractions.Wrappers&package-manager=nuget&previous-version=22.0.15&new-version=22.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
###### Microsoft Reviewers: [Open in
CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/Azure/bicep/pull/19832)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state: released Issues that are released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MockFileSystem incorrectly allows shared access to same file

3 participants