///|
#cfg(target="native")
async test "open file for reading" {
let test_file = "_build/test_open_read.txt"
@fs.write_file(test_file, b"Hello, MoonBit!")
defer @fs.remove(test_file)
let file = @fs.open(test_file, mode=ReadOnly)
defer file.close()
let content = file.read_all().text()
inspect(content, content="Hello, MoonBit!")
}
///|
#cfg(target="native")
async test "open file for writing" {
let test_file = "_build/test_open_write.txt"
let file = @fs.open(test_file, mode=WriteOnly, create_mode=CreateOrTruncate)
defer @fs.remove(test_file)
defer file.close()
file.write(b"Hello, World!")
}
///|
#cfg(target="native")
async test "open with append mode" {
let test_file = "_build/test_append.txt"
// Create initial file
@fs.write_file(test_file, b"First line\n")
defer @fs.remove(test_file)
// Append to existing file
{
let file = @fs.open(test_file, mode=WriteOnly, append=true)
defer file.close()
file.write(b"Second line\n")
}
let content = @fs.read_file(test_file).text()
inspect(content, content="First line\nSecond line\n")
}///|
#cfg(target="native")
async test "create new file" {
let test_file = "_build/test_create.txt"
let file = @fs.create(test_file)
defer @fs.remove(test_file)
{
defer file.close()
file.write(b"New file content")
}
let exists = @fs.exists(test_file)
inspect(exists, content="true")
}///|
#cfg(target="native")
async test "read_file - read entire file" {
let test_file = "_build/test_read_file.txt"
@fs.write_file(test_file, b"Hello, MoonBit!")
defer @fs.remove(test_file)
let content = @fs.read_file(test_file)
inspect(content.text(), content="Hello, MoonBit!")
}
///|
#cfg(target="native")
async test "read in chunks using File" {
let test_file = "_build/test_chunk_read.txt"
@fs.write_file(test_file, b"0123456789")
defer @fs.remove(test_file)
let file = @fs.open(test_file, mode=ReadOnly)
defer file.close()
let buf = FixedArray::make(5, b'0')
let n = file.read(buf)
inspect(n, content="5")
inspect(@utf8.decode(buf.unsafe_reinterpret_as_bytes()), content="01234")
}
///|
#cfg(target="native")
async test "read_all from file" {
let test_file = "_build/test_read_all.txt"
@fs.write_file(test_file, b"Complete content")
defer @fs.remove(test_file)
let file = @fs.open(test_file, mode=ReadOnly)
defer file.close()
let data = file.read_all()
inspect(data.text(), content="Complete content")
}
///|
#cfg(target="native")
async test "read_exactly specific bytes" {
let test_file = "_build/test_read_exact.txt"
@fs.write_file(test_file, b"1234567890")
defer @fs.remove(test_file)
let file = @fs.open(test_file, mode=ReadOnly)
defer file.close()
let bytes = file.read_exactly(5)
inspect(@utf8.decode(bytes), content="12345")
}///|
#cfg(target="native")
async test "write_file - write entire file" {
let test_file = "_build/test_write.txt"
@fs.write_file(test_file, b"File content")
defer @fs.remove(test_file)
let content = @fs.read_file(test_file).text()
inspect(content, content="File content")
}
///|
#cfg(target="native")
async test "write with sync modes" {
let test_file = "_build/test_sync.txt"
// Write with data sync
@fs.write_file(test_file, b"Synced data", sync=Data)
defer @fs.remove(test_file)
let content = @fs.read_file(test_file).text()
inspect(content, content="Synced data")
}
///|
#cfg(target="native")
async test "write using File methods" {
let test_file = "_build/test_file_write.txt"
let file = @fs.create(test_file)
defer @fs.remove(test_file)
{
defer file.close()
file.write(b"Line 1\n")
file.write(b"Line 2\n")
}
let content = @fs.read_file(test_file).text()
inspect(content, content="Line 1\nLine 2\n")
}
///|
#cfg(target="native")
async test "write_once for single write operation" {
let test_file = "_build/test_write_once.txt"
let file = @fs.create(test_file)
defer @fs.remove(test_file)
defer file.close()
let data : Bytes = b"Single write"
let written = file.write_once(data, offset=0, len=data.length())
inspect(written, content="12")
}///|
#cfg(target="native")
async test "read at specific position" {
let test_file = "_build/read_at_test.txt"
@fs.write_file(test_file, b"0123456789")
defer @fs.remove(test_file)
let file = @fs.open(test_file, mode=ReadOnly)
defer file.close()
// read 3 bytes at position 5
json_inspect(file.read_exactly_at(3, position=5), content="567")
// use `read_at` to handle EOF robustly
let buf = FixedArray::make(10, b'\x00')
let n = file.read_at(buf, position=5)
inspect(n, content="5")
json_inspect(buf.unsafe_reinterpret_as_bytes()[:n], content="56789")
}
///|
#cfg(target="native")
async test "write at specific position" {
let test_file = "_build/write_at_test.txt"
let file = @fs.open(test_file, mode=WriteOnly, create_mode=CreateOrTruncate)
defer @fs.remove(test_file)
{
defer file.close()
file.write("abcdef")
file.write_at(b"CD", position=2)
}
// read 3 bytes at position 5
inspect(@fs.read_file(test_file).text(), content="abCDef")
}
///|
#cfg(target="native")
async test "size - get file size" {
let test_file = "_build/test_size.txt"
@fs.write_file(test_file, b"Hello")
defer @fs.remove(test_file)
let file = @fs.open(test_file, mode=ReadOnly)
defer file.close()
let size = file.size()
inspect(size, content="5")
}///|
#cfg(target="native")
async test "mkdir - create directory" {
let dir_path = "_build/test_mkdir"
@fs.mkdir(dir_path, permission=0o755)
defer @fs.rmdir(dir_path)
let exists = @fs.exists(dir_path)
inspect(exists, content="true")
}
///|
#cfg(target="native")
async test "mkdir - create with custom permissions" {
let dir_path = "_build/test_mkdir_perm"
@fs.mkdir(dir_path, permission=0o700)
defer @fs.rmdir(dir_path)
let kind = @fs.kind(dir_path)
debug_inspect(kind, content="Directory")
}///|
#cfg(target="native")
async test "readdir - read directory entries" {
let dir_path = "_build/test_readdir"
@fs.mkdir(dir_path, permission=0o755)
defer @fs.rmdir(dir_path, recursive=true)
@fs.write_file("\{dir_path}/test1.txt", b"")
@fs.write_file("\{dir_path}/test2.txt", b"")
let entries = @fs.readdir(
dir_path,
include_hidden=false,
include_special=false,
)
// avoid platform inconsistent ordering
entries.sort()
json_inspect(entries, content=["test1.txt", "test2.txt"])
}
///|
#cfg(target="native")
async test "readdir with sorting" {
let dir_path = "_build/test_readdir_sort"
@fs.mkdir(dir_path, permission=0o755)
defer @fs.rmdir(dir_path, recursive=true)
@fs.write_file("\{dir_path}/c.txt", b"")
@fs.write_file("\{dir_path}/a.txt", b"")
@fs.write_file("\{dir_path}/b.txt", b"")
let entries = @fs.readdir(dir_path, sort=true)
json_inspect(entries, content=["a.txt", "b.txt", "c.txt"])
}
///|
#cfg(target="native")
async test "opendir and Directory::read_all" {
let dir_path = "_build/test_opendir"
@fs.mkdir(dir_path, permission=0o755)
defer @fs.rmdir(dir_path, recursive=true)
@fs.write_file("\{dir_path}/file1.txt", b"test")
@fs.write_file("\{dir_path}/file2.txt", b"test")
let dir = @fs.opendir(dir_path)
defer dir.close()
let entries = dir
.read_all(include_hidden=false, include_special=false)
..sort()
json_inspect(entries, content=["file1.txt", "file2.txt"])
}///|
#cfg(target="native")
async test "walk directory tree" {
let base = "_build/test_walk"
@fs.mkdir(base)
defer @fs.rmdir(base, recursive=true)
@fs.mkdir("\{base}/sub1")
@fs.mkdir("\{base}/sub2")
@fs.write_file("\{base}/file.txt", b"")
@fs.write_file("\{base}/sub1/file1.txt", b"")
let visited : Ref[Int] = Ref(0)
@fs.walk(base, fn(_path, _files) { visited.val = visited.val + 1 })
inspect(visited.val >= 3, content="true")
}
///|
#cfg(target="native")
async test "walk with max_concurrency" {
let base = "_build/test_walk_concurrency"
@fs.mkdir(base, permission=0o755)
defer @fs.rmdir(base, recursive=true)
@fs.mkdir("\{base}/dir1", permission=0o755)
@fs.mkdir("\{base}/dir2", permission=0o755)
let count : Ref[Int] = Ref(0)
@fs.walk(
base,
fn(_path, _files) { count.val = count.val + 1 },
max_concurrency=1,
)
inspect(count.val >= 3, content="true")
}///|
#cfg(target="native")
async test "rmdir - remove empty directory" {
let dir_path = "_build/test_rmdir"
@fs.mkdir(dir_path)
@fs.rmdir(dir_path)
let exists = @fs.exists(dir_path)
inspect(exists, content="false")
}
///|
#cfg(target="native")
async test "rmdir recursive - remove directory tree" {
let base = "_build/test_rmdir_recursive"
@fs.mkdir(base)
@fs.mkdir("\{base}/subdir")
@fs.write_file("\{base}/file.txt", b"test")
@fs.write_file("\{base}/subdir/nested.txt", b"test")
@fs.rmdir(base, recursive=true)
let exists = @fs.exists(base)
inspect(exists, content="false")
}///|
#cfg(target="native")
async test "kind - regular file" {
let test_file = "_build/test_kind_file.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let kind = @fs.kind(test_file)
debug_inspect(kind, content="Regular")
}
///|
#cfg(target="native")
async test "kind - directory" {
let dir_path = "_build/test_kind_dir"
@fs.mkdir(dir_path, permission=0o755)
defer @fs.rmdir(dir_path)
let kind = @fs.kind(dir_path)
debug_inspect(kind, content="Directory")
}
///|
#cfg(target="native")
async test "File::kind method" {
let test_file = "_build/test_file_kind.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let file = @fs.open(test_file, mode=ReadOnly)
defer file.close()
let kind = file.kind()
debug_inspect(kind, content="Regular")
}///|
#cfg(all(target="native", not(platform="windows")))
async test "atime - access time" {
let test_file = "_build/test_atime.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let (seconds, nanoseconds) = @fs.atime(test_file)
inspect(seconds > 0, content="true")
inspect(nanoseconds >= 0, content="true")
}
///|
#cfg(target="native")
async test "mtime - modification time" {
let test_file = "_build/test_mtime.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let (seconds, nanoseconds) = @fs.mtime(test_file)
inspect(seconds > 0, content="true")
inspect(nanoseconds >= 0, content="true")
}
///|
#cfg(target="native")
async test "ctime - status change time" {
let test_file = "_build/test_ctime.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let (seconds, nanoseconds) = @fs.ctime(test_file)
inspect(seconds > 0, content="true")
inspect(nanoseconds >= 0, content="true")
}
///|
#cfg(target="native")
async test "File timestamp methods" {
let test_file = "_build/test_file_times.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let file = @fs.open(test_file, mode=ReadOnly)
defer file.close()
let (atime_s, _) = file.atime()
let (mtime_s, _) = file.mtime()
let (ctime_s, _) = file.ctime()
inspect(atime_s > 0, content="true")
inspect(mtime_s > 0, content="true")
inspect(ctime_s > 0, content="true")
}///|
#cfg(target="native")
async test "exists - check file existence" {
let test_file = "_build/test_exists.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let exists = @fs.exists(test_file)
inspect(exists, content="true")
}
///|
#cfg(target="native")
async test "exists - non-existent file" {
let exists = @fs.exists("nonexistent_file_xyz.txt")
inspect(exists, content="false")
}
///|
#cfg(target="native")
async test "can_read - check read permission" {
let test_file = "_build/test_can_read.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let can_read = @fs.can_read(test_file)
inspect(can_read, content="true")
}
///|
#cfg(target="native")
async test "can_write - check write permission" {
let test_file = "_build/test_can_write.txt"
@fs.write_file(test_file, b"test")
defer @fs.remove(test_file)
let can_write = @fs.can_write(test_file)
inspect(can_write, content="true")
}
///|
#cfg(target="native")
async test "can_execute - check execute permission" {
let test_file = "_build/test_can_execute.txt"
@fs.write_file(test_file, b"test", create_mode=CreateNew, permission=0o755)
defer @fs.remove(test_file)
let can_execute = @fs.can_execute(test_file)
inspect(can_execute, content="true")
}///|
#cfg(target="native")
async test "get file size by path" {
let test_file = "_build/test_size_by_path.txt"
@fs.write_file(test_file, b"Hello")
inspect(@fs.file_size(test_file), content="5")
}///|
#cfg(target="native")
async test "realpath - resolve absolute path" {
let test_dir = "_build/test_realpath"
@fs.mkdir(test_dir)
defer @fs.rmdir(test_dir)
let real_path = @fs.realpath(test_dir)
@env.current_dir() is Some(cwd)
assert_true(real_path.has_prefix(cwd))
inspect(
// replace `\\` with `/` for Windows
real_path[cwd.length():].replace_all(old="\\", new="/"),
content="/_build/test_realpath",
)
}///|
#cfg(target="native")
async test "remove - delete file" {
let test_file = "_build/test_remove.txt"
@fs.write_file(test_file, b"test")
defer (if @fs.exists(test_file) { @fs.remove(test_file) })
@fs.remove(test_file)
let exists = @fs.exists(test_file)
inspect(exists, content="false")
}///|
#cfg(target="native")
async fn watch_project_sources() -> Unit {
let watcher = @fs.Watcher("src", ignored_paths=path => {
path.has_prefix("_build/")
})
defer watcher.close()
while watcher.wait() is events {
debug(events)
}
}///|
#cfg(target="native")
async test "error handling example" {
@test_util.assert_raise_async(() => @fs.read_file("nonexistent.txt"))
}pub(all) enum CreateMode {
OpenExisting
TruncateExisting
OpenOrCreate
CreateOrTruncate
CreateNew
}type Directoryasync fn Directory::next(dir : Directory, include_hidden? : Bool, include_special? : Bool) -> DirectoryEntry?type Filepub(all) enum Lock {
Shared
Exclusive
}pub(all) enum SyncMode {
NoSync
Data
Full
}type Watcherasync fn atime(path : StringView, follow_symlink? : Bool) -> (Int64, Int)async fn chmod(path : StringView, mode : Int) -> Unitasync fn ctime(path : StringView, follow_symlink? : Bool) -> (Int64, Int)async fn file_size(path : StringView) -> Int64async fn mkdir(path : StringView, permission? : Int, recursive? : Bool, allow_exist? : Bool) -> Unitasync fn mtime(path : StringView, follow_symlink? : Bool) -> (Int64, Int)async fn open(filename : StringView, mode~ : Mode, sync? : SyncMode, append? : Bool, create_mode? : CreateMode, permission? : Int) -> Fileasync fn readdir(path : StringView, include_hidden? : Bool, include_special? : Bool, sort? : Bool) -> Array[String]async fn realpath(path : StringView) -> Stringasync fn remove(path : StringView) -> Unit nocancelasync fn rename(old_path : StringView, new_path : StringView, replace? : Bool) -> Unitasync fn rmdir(path : StringView, recursive? : Bool) -> Unit nocancelasync fn symlink(target~ : StringView, path : StringView, force_symlink? : Bool) -> Unitasync fn tmpdir(prefix~ : StringView) -> Stringasync fn walk(path : StringView, f : async (String, Array[String]) -> Unit, exclude? : (String) -> Bool, max_concurrency? : Int, allow_failure? : Bool) -> Unitasync fn write_file(path : StringView, content : &Data, create_mode? : CreateMode, permission? : Int, sync? : SyncMode, append? : Bool) -> UnitInstall
Download zipAsynchronous programming library for MoonBit