Repository: libfuse/python-fuse (language: python)

Issue:
When getting string size, count UTF8 bytes
.. rather than Unicode code points.

Closes #77

This also fixes some warnings & changes additional references to my e-mail address.


Discussion / hints:
@jepler thanks a lot, please visit more often ;)

Fix patch:
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 2ab6b76..d824689 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -23,7 +23,7 @@ jobs:
         run: python -c "import sys; print(sys.version)"
 
       - name: Install Python build dependencies
-        run: python -m pip install --upgrade pip setuptools wheel
+        run: python -m pip install --upgrade pip setuptools wheel pytest
 
       - name: Install libfuse-dev and pkg-config
         run: sudo apt install -y libfuse-dev pkg-config
@@ -34,5 +34,4 @@ jobs:
       - name: Test
         run: |
           sudo modprobe fuse
-          mkdir /tmp/foo && python example/hello.py /tmp/foo && [ "$(cat /tmp/foo/hello)" = "Hello World!" ]
-          mkdir /tmp/bar && python example/fioc.py /tmp/bar && [ -f /tmp/bar/fioc ]
+          python -m pytest
diff --git a/example/fioc.py b/example/fioc.py
index e4b81bb..485a8b0 100644
--- a/example/fioc.py
+++ b/example/fioc.py
@@ -71,6 +71,7 @@ def _IOWR(cls,t,nr,size):
 FIOC_GET_SIZE = IOCTL._IOR(ord('E'),0, struct.calcsize("L"));
 FIOC_SET_SIZE = IOCTL._IOW(ord('E'),1, struct.calcsize("L"));
 
+print(f"{FIOC_GET_SIZE:x} {FIOC_SET_SIZE:x}")
 # object type
 FIOC_NONE = 0
 FIOC_ROOT = 1


Test patch:
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..90dddf3
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+markers =
+    fstype: Type of filesystem to mount
diff --git a/tests/test_basic.py b/tests/test_basic.py
new file mode 100644
index 0000000..380ce30
--- /dev/null
+++ b/tests/test_basic.py
@@ -0,0 +1,63 @@
+import os
+import time
+import sys
+import struct
+import subprocess
+import pathlib
+import tempfile
+import pytest
+import fcntl
+
+topdir = pathlib.Path(__file__).parent.parent
+
+@pytest.fixture
+def filesystem(request):
+    fstype = request.node.get_closest_marker("fstype").args[0]
+
+    with tempfile.TemporaryDirectory() as tmpdir:
+        st_dev = os.stat(tmpdir).st_dev
+        proc = subprocess.Popen([sys.executable, "-d", topdir / "example" / f"{fstype}.py", tmpdir], stdin=subprocess.DEVNULL)
+
+        deadline = time.time() + 1
+        while time.time() < deadline:
+            new_st_dev = os.stat(tmpdir).st_dev
+            if new_st_dev != st_dev:
+                break
+            time.sleep(.01)
+        if new_st_dev == st_dev:
+            proc.terminate()
+            raise RuntimeError("Filesystem did not mount within 1s")
+
+
+        yield pathlib.Path(tmpdir)
+
+        subprocess.call(["fusermount", "-u", "-q", "-z", tmpdir])
+
+        deadline = time.time() + 1
+        while time.time() < deadline:
+            result = proc.poll()
+            if result is not None:
+                if result != 0:
+                    raise RuntimeError("Filesystem exited with an error: {result}")
+                return
+            time.sleep(.01)
+
+        proc.terminate()
+        raise RuntimeError("Filesystem failed to exit within 1s after unmount")
+
+@pytest.mark.fstype("hello")
+def test_hello(filesystem):
+    content = (filesystem / "hello").read_text(encoding="utf-8")
+    assert content == "Hello World!\n"
+
+@pytest.mark.fstype("fioc")
+def test_fioc(filesystem):
+    FIOC_GET_SIZE, FIOC_SET_SIZE = 0x80084500, 0x40084501
+    with (filesystem / "fioc").open("rb") as f:
+        b = struct.pack("L", 42)
+        fcntl.ioctl(f.fileno(), FIOC_SET_SIZE, b)
+
+        b = bytearray(struct.calcsize('l'))
+        fcntl.ioctl(f.fileno(), FIOC_GET_SIZE, b)
+        assert struct.unpack("L", b)[0] == 42
+