1# Test VfsFat class and its finaliser
2
3try:
4    import uerrno, uos
5
6    uos.VfsFat
7except (ImportError, AttributeError):
8    print("SKIP")
9    raise SystemExit
10
11
12class RAMBlockDevice:
13    def __init__(self, blocks, sec_size=512):
14        self.sec_size = sec_size
15        self.data = bytearray(blocks * self.sec_size)
16
17    def readblocks(self, n, buf):
18        for i in range(len(buf)):
19            buf[i] = self.data[n * self.sec_size + i]
20
21    def writeblocks(self, n, buf):
22        for i in range(len(buf)):
23            self.data[n * self.sec_size + i] = buf[i]
24
25    def ioctl(self, op, arg):
26        if op == 4:  # MP_BLOCKDEV_IOCTL_BLOCK_COUNT
27            return len(self.data) // self.sec_size
28        if op == 5:  # MP_BLOCKDEV_IOCTL_BLOCK_SIZE
29            return self.sec_size
30
31
32# Create block device, and skip test if not enough RAM
33try:
34    bdev = RAMBlockDevice(50)
35except MemoryError:
36    print("SKIP")
37    raise SystemExit
38
39# Format block device and create VFS object
40uos.VfsFat.mkfs(bdev)
41vfs = uos.VfsFat(bdev)
42
43# Here we test that opening a file with the heap locked fails correctly.  This
44# is a special case because file objects use a finaliser and allocating with a
45# finaliser is a different path to normal allocation.  It would be better to
46# test this in the core tests but there are no core objects that use finaliser.
47import micropython
48
49micropython.heap_lock()
50try:
51    vfs.open("x", "r")
52except MemoryError:
53    print("MemoryError")
54micropython.heap_unlock()
55
56# Here we test that the finaliser is actually called during a garbage collection.
57import gc
58
59N = 4
60for i in range(N):
61    n = "x%d" % i
62    f = vfs.open(n, "w")
63    f.write(n)
64    f = None  # release f without closing
65    [0, 1, 2, 3]  # use up Python stack so f is really gone
66gc.collect()  # should finalise all N files by closing them
67for i in range(N):
68    with vfs.open("x%d" % i, "r") as f:
69        print(f.read())
70