diff --git a/website/articles/fstest-mapfs-file-does-not-exist.html b/website/articles/fstest-mapfs-file-does-not-exist.html index 642c2c0..cd8b05b 100644 --- a/website/articles/fstest-mapfs-file-does-not-exist.html +++ b/website/articles/fstest-mapfs-file-does-not-exist.html @@ -17,22 +17,54 @@
+

The problem

- In my tests, I defined an fstest.MapFS like this + I rewrote my tests to use an fstest.MapFS, defined like this -

-contentRoot := fstest.MapFS{
-            "/parentDir/index.html": &fstest.MapFile{Data: []byte("content"), Mode: 0o755},
-            "/parentDir/childDir/1-2-3.html": &fstest.MapFile{Data: []byte("other content"`), Mode: 0o755},
-        }
-    
+
contentRoot := fstest.MapFS{
+    "/parentDir/index.html": &fstest.MapFile{Data: []byte("content"), Mode: 0o755},
+    "/parentDir/childDir/1-2-3.html": &fstest.MapFile{Data: []byte("other content"`), Mode: 0o755},
+}
- Simple, and yet when I ran a test against it, I received this error: + + Simple, and yet when I ran a test against it, I received this error: + +
2024/03/27 19:42:59 http: panic serving [::1]:57135: open parentDir: file does not exist
+
+

+
+ +
+

The setup

+

+ I wrote this comment a few days ago and haven't thought much about it since: -

-2024/03/27 19:42:59 http: panic serving [::1]:57135: open parentDir: file does not exist
-    
+
+// /index.html becomes index.html
+// /articles/page.html becomes articles/page.html
+// without this the paths aren't found properly inside the fs.
+pagePath = strings.TrimPrefix(pagePath, "/")
+pageContent, err := fs.ReadFile(a.SiteFiles, pagePath)
+
+ + pagePath is retrieved from an http GET, and always starts with a "/"; I don't want to be seeking for an absolute + path inside the os.DirFS because the file won't be found. +

+ +

+ ReadFile dispatches to the a.SiteFiles implementation of the Open function, so the os.DirFS controls lookup of the file. You + can see that in the official source: + +

func ReadFile(fsys FS, name string) ([]byte, error) {
+if fsys, ok := fsys.(ReadFileFS); ok {
+    return fsys.ReadFile(name)
+}
+    
+file, err := fsys.Open(name)
+

+ +

@@ -43,31 +75,23 @@

What's the misunderstanding?

This one took me a couple of hours to finally understand.

- An fstest.MapFS is pretty much a hash map. If you don't have a precise match for the key in the map - then you get a file does not exist error. Here's the implementation that shows that: + An fstest.MapFS is a hash map. Its implementation of Open() is very simple: -

-        file := fsys[name]
-    
-- reference in the go source code. +
file := fsys[name]
+ - reference in the go source code.
+ +It simply looks up the key in the hashmap, and I was manipulating that key to remove a leading slash.

What's the fix?

- - In my case, I was performing some path munging in my logic so that I was searching for paths relatively, not absolutely - using a leading "/", so my search string was "parentDir/index.html". -

-

- Once I understood that the path in the fstest.MapFS does not need to be an absolute path, because it is only - a key in a hash map, I redefined my structure like this and got my tests passing: + Once I understood that the path in the fstest.MapFS is only a map key, I realised it does not need to be an absolute path. + I redefined it like this and got my tests passing: -

-contentRoot := fstest.MapFS{
-            "/parentDir/index.html": &fstest.MapFile{Data: []byte("content"), Mode: 0o755},
-            "/parentDir/childDir/1-2-3.html": &fstest.MapFile{Data: []byte("other content"`), Mode: 0o755},
-        }
-    
+
contentRoot := fstest.MapFS{
+"parentDir/index.html": &fstest.MapFile{Data: []byte("content"), Mode: 0o755},
+"parentDir/childDir/1-2-3.html": &fstest.MapFile{Data: []byte("other content"`), Mode: 0o755},
+}