Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FakeFileSystem incorrect file size on conversion to File #1429

Closed
arturdryomov opened this issue Feb 12, 2024 · 2 comments
Closed

FakeFileSystem incorrect file size on conversion to File #1429

arturdryomov opened this issue Feb 12, 2024 · 2 comments

Comments

@arturdryomov
Copy link

When using FakeFileSystem, the Path#toFile() works fine but calling length() on the resulting File always results in 0. For example, the following test fails:

@Test
fun checkFileSize() {
    FakeFileSystem().let { fs ->
        val rootPath = "root".toPath().apply {
            fs.createDirectory(this)
        }

        val textPath = rootPath.resolve("file.txt")

        fs.write(textPath) {
            writeUtf8("fake")
            flush()
        }

        assertEquals(fs.metadata(textPath).size!!, textPath.toFile().length())
    }
}
Expected :4
Actual   :0

I’m not sure if a workaround is possible though since it’s not possible to pass a file size into the File constructor or set it. As far as I can see, under the hood File uses DefaultFileSystem.getFileSystem() on recent JDKs so a FS swap is not possible as well.

Overall, is it a known behavior / caveat when working with FakeFileSystem?

@JakeWharton
Copy link
Member

In Okio, the path is a value which represents just that: the file path. There is no intrinsic information that ties it to a particular file system. This is in contrast to java.io.File which is tied to the system file system, or java.nio.file.Path which is tied to a particular java.nio.file.FileSystem.

If you have a path which represents /tmp/hello.txt and I have the same path, reading the file will (probably) produce different results because we have different machines. The path is the same value, the file system is the system file system on both machines but the machines are different. The path doesn't know that, though, and is likely valid on both (or any) machine.

If you have the path META-INT/MANIFEST.MF and you read it from two different .jar files (using zip filesystem) you'll get different results. The path is the same, but the file system is different. The path doesn't know that, it's valid anywhere since it's just a value.

In your case, you have a path /root/file.txt and you are writing to that on the fake file system instance and then attempting to read it from the system file system (by virtue of first converting it to a File). You are writing in one place and reading from another.

The only time toFile() will return a File that points to the same reference is if you were using FileSystem.SYSTEM.

Another way to think about it is to create two instances of FakeFileSystem. If you write to one and then read from the other you will not see the correct size.

By calling toFile() you are taking the path and passing it to a different system that only knows how to read from the system file system.

@arturdryomov
Copy link
Author

Thanks for the detailed and awesome explanation!

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

No branches or pull requests

2 participants