base() {
	mkdir "$1/dir"
	echo "hello, world" >"$1/dir/file"
}

unmodified() {
	true
}

create_empty_file() {
	touch "$1/dir/newfile"
}

create_file() {
	echo "lorem ipsum" >"$1/dir/newfile"
	[ -r "$1/dir/newfile" ]
	[ -w "$1/dir/newfile" ]
	[ ! -x "$1/dir/newfile" ]
}

create_executable_file() {
	echo "#!/bin/true" >"$1/dir/executable"
	chmod a+x "$1/dir/executable"
	[ -x "$1/dir/executable" ]
}

append_file() {
	echo "lorem ipsum" >>"$1/dir/file"
}

truncate_file() {
	truncate --size=4 "$1/dir/file"
	mtime1="$(stat -c %y "$1/dir/file")"
	sleep 1
	truncate --size=4 "$1/dir/file"
	mtime2="$(stat -c %y "$1/dir/file")"
	# Verify that truncate updates the mtime
	[ "$mtime1" != "$mtime2" ]
}

fallocate_file() {
	fallocate -o 5 -l 42 "$1/dir/file"
}

rename_file() {
	mv "$1/dir/file" "$1/dir/renamed"
}

rename_file_crossdir() {
	mkdir "$1/dir2"
	mv "$1/dir/file" "$1/dir2/renamed"
}

rename_file_noreplace() {
	echo "lorem ipsum" >"$1/dir/newfile"
	mv --no-clobber "$1/dir/newfile" "$1/dir/file" || true
}

rename_file_noreplace_crossdir() {
	mkdir "$1/dir2"
	echo "lorem ipsum" >"$1/dir2/newfile"
	mv --no-clobber "$1/dir2/newfile" "$1/dir/file" || true
}

replace_file() {
	echo "lorem ipsum" >"$1/dir/newfile"
	mv "$1/dir/newfile" "$1/dir/file"
}

replace_file_crossdir() {
	mkdir "$1/dir2"
	echo "lorem ipsum" >"$1/dir2/newfile"
	mv "$1/dir2/newfile" "$1/dir/file"
}

remove_file() {
	rm "$1/dir/file"
}

create_empty_directory() {
	mkdir "$1/dir/subdir"
	# Directory listings should include `.` and `..`
	[ $(ls -a "$1/dir/subdir" | wc -l) = 2 ]
}

create_directory_with_file() {
	mkdir "$1/dir/subdir"
	echo "lorem ipsum" >"$1/dir/subdir/newfile"
}

remove_directory() {
	rm -r "$1/dir"
}

create_symlink() {
	ln -s "file" "$1/dir/symlink"
}

create_hardlink() {
	ln "$1/dir/file" "$1/dir/hardlink"
}

chown_ctime() {
	ctime1="$(stat -c %z "$1/dir/file")"
	sleep 1
	chown $(id -u) "$1/dir/file"
	ctime2="$(stat -c %z "$1/dir/file")"
	# Verify that chown updates the ctime
	[ "$ctime1" != "$ctime2" ]
}

atime() {
	ctime1="$(stat -c %z "$1/dir/file")"
	atime1="$(stat -c %x "$1/dir/file")"
	sleep 1
	touch -a "$1/dir/file"
	ctime2="$(stat -c %z "$1/dir/file")"
	atime2="$(stat -c %x "$1/dir/file")"
	# Verify that touch -a updates the atime and the ctime
	[ "$atime1" != "$atime2" ]
	[ "$ctime1" != "$ctime2" ]

	sleep 1
	cat "$1/dir/file" >/dev/null
	ctime3="$(stat -c %z "$1/dir/file")"
	atime3="$(stat -c %x "$1/dir/file")"
	# Verify that reading the file updates the atime but not the ctime
	[ "$atime2" != "$atime3" ]
	[ "$ctime2" = "$ctime3" ]
}

fifo() {
	mkfifo "$1/dir/fifo"
	echo "lorem ipsum" >"$1/dir/fifo" &
	read line <"$1/dir/fifo"
	[ "$line" = "lorem ipsum" ]
	rm "$1/dir/fifo"
}

chmod_perms() {
	[ -r "$1/dir/file" ]
	chmod 0 "$1/dir/file"
	[ ! -r "$1/dir/file" ]
	# Verify that the file cannot be read by attempting to copy it
	! cp "$1/dir/file" "$1/copy"
	chmod 0644 "$1/dir/file"
	[ -r "$1/dir/file" ]
}
