fusio 0.6.0

Fusio provides lean, minimal cost abstraction and extensible Read / Write trait to multiple storage on multiple poll-based / completion-based async runtime.
Documentation
#[cfg(test)]
#[cfg(all(feature = "opfs", target_arch = "wasm32"))]
pub(crate) mod tests {

    wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);

    use fusio::{
        disk::OPFS,
        fs::{CasCondition, FsCas, OpenOptions},
        path::Path,
        DynFs, Read, Write,
    };
    use futures_util::StreamExt;
    use wasm_bindgen_test::wasm_bindgen_test;

    async fn remove_all(fs: &OPFS, pathes: &[&str]) {
        for path in pathes {
            fs.remove(&(*path).into()).await.unwrap();
        }
    }

    #[wasm_bindgen_test]
    async fn test_opfs_list() {
        let fs = OPFS;
        let path = "test_opfs_dir".to_string();
        fs.create_dir_all(&path.into()).await.unwrap();
        let mut file1 = fs
            .open_options(&"file1".into(), OpenOptions::default().create(true))
            .await
            .unwrap();
        let mut file2 = fs
            .open_options(&"file2".into(), OpenOptions::default().create(true))
            .await
            .unwrap();
        file1.close().await.unwrap();
        file2.close().await.unwrap();

        let base_path = Path::from_opfs_path("/".to_string()).unwrap();
        let mut stream = fs.list(&base_path).await.unwrap();
        let mut result_len = 0;
        let expected = ["test_opfs_dir", "file1", "file2"];
        while let Some(Ok(meta)) = stream.next().await {
            assert!(expected.contains(&meta.path.as_ref()));
            result_len += 1;
        }
        assert_eq!(result_len, 3);

        remove_all(&fs, &["test_opfs_dir", "file1", "file2"]).await;
    }

    #[wasm_bindgen_test]
    async fn test_create_nested_entry() {
        let fs = OPFS;
        let path = Path::from_opfs_path("test_opfs_dir/sub_dir".to_string()).unwrap();
        fs.create_dir_all(&path).await.unwrap();
        let mut file1 = fs
            .open_options(
                &Path::from_opfs_path("test_opfs_dir/file").unwrap(),
                OpenOptions::default().create(true),
            )
            .await
            .unwrap();
        let mut file2 = fs
            .open_options(
                &Path::from_opfs_path("test_opfs_dir/sub_dir/sub_file").unwrap(),
                OpenOptions::default().create(true),
            )
            .await
            .unwrap();
        file1.close().await.unwrap();
        file2.close().await.unwrap();

        let base_path = Path::from_opfs_path("test_opfs_dir".to_string()).unwrap();
        let mut stream = fs.list(&base_path).await.unwrap();
        let expected = ["test_opfs_dir/sub_dir", "test_opfs_dir/file"];
        let mut result_len = 0;
        while let Some(Ok(meta)) = stream.next().await {
            assert!(expected.contains(&meta.path.as_ref()));
            result_len += 1;
        }
        assert_eq!(result_len, 2);

        fs.remove(&Path::from_opfs_path("test_opfs_dir/file").unwrap())
            .await
            .unwrap();

        let expected = ["test_opfs_dir/sub_dir"];
        let mut result_len = 0;
        let mut stream = fs.list(&base_path).await.unwrap();
        while let Some(Ok(meta)) = stream.next().await {
            assert!(expected.contains(&meta.path.as_ref()));
            result_len += 1;
        }
        assert_eq!(result_len, 1);

        remove_all(&fs, &["test_opfs_dir"]).await;
    }

    #[wasm_bindgen_test]
    async fn test_opfs_read_write() {
        let fs = OPFS;
        let mut file = fs
            .open_options(
                &"file".into(),
                OpenOptions::default().create(true).truncate(true),
            )
            .await
            .unwrap();
        let (result, _) = file.write_all([1, 2, 3, 4].as_mut()).await;
        result.unwrap();
        let (result, _) = file.write_all([11, 23, 34, 47].as_mut()).await;
        result.unwrap();
        let (result, _) = file.write_all([121, 93, 94, 97].as_mut()).await;
        result.unwrap();
        file.close().await.unwrap();

        let mut file = fs
            .open_options(&"file".into(), OpenOptions::default())
            .await
            .unwrap();
        let expected = [1_u8, 2, 3, 4, 11, 23, 34, 47, 121, 93, 94, 97];
        for i in 0..12 {
            let (result, data) = file.read_to_end_at(vec![], i).await;
            result.unwrap();
            assert_eq!(data.as_slice(), &expected[i as usize..]);
        }

        let mut buf = [0; 7];
        let (result, data) = file.read_exact_at(buf.as_mut(), 3).await;
        result.unwrap();
        assert_eq!(data, [4, 11, 23, 34, 47, 121, 93]);
        remove_all(&fs, &["file"]).await;
    }

    #[wasm_bindgen_test]
    async fn test_opfs_read_write_utf16() {
        let fs = OPFS;
        let mut file = fs
            .open_options(
                &"file".into(),
                OpenOptions::default().create(true).truncate(true),
            )
            .await
            .unwrap();
        let utf16_bytes: &[u8] = &[
            0x00, 0x48, 0x20, 0xAC, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x77,
            0x00, 0x6f, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x21,
        ];

        let (result, _) = file.write_all(utf16_bytes).await;
        result.unwrap();
        file.close().await.unwrap();

        let mut file = fs
            .open_options(&"file".into(), OpenOptions::default())
            .await
            .unwrap();
        let (result, data) = file.read_to_end_at(vec![], 0).await;
        result.unwrap();
        assert_eq!(
            data,
            [
                0x00, 0x48, 0x20, 0xAC, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x77,
                0x00, 0x6f, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x21,
            ]
        );

        remove_all(&fs, &["file"]).await;
    }

    #[wasm_bindgen_test]
    async fn test_opfs_read_eof() {
        let fs = OPFS;
        let mut file = fs
            .open_options(
                &"file".into(),
                OpenOptions::default().create(true).truncate(true),
            )
            .await
            .unwrap();

        let mut buf = [0; 1];
        let (result, _) = file.read_exact_at(buf.as_mut(), 0).await;
        assert!(result.is_err());

        let (result, _) = file.write_all([1, 2, 3, 4].as_mut()).await;
        result.unwrap();
        file.close().await.unwrap();

        let mut file = fs
            .open_options(&"file".into(), OpenOptions::default())
            .await
            .unwrap();

        let mut buf = [0; 1];
        let (result, data) = file.read_exact_at(buf.as_mut(), 5).await;
        assert!(result.is_err());
        assert_eq!(data, [0]);
        remove_all(&fs, &["file"]).await;
    }

    #[wasm_bindgen_test]
    async fn test_opfs_cas_semantics() {
        let fs = OPFS;
        let path = Path::from_opfs_path("cas/head.json").unwrap();

        let _ = fs.remove(&path).await;

        let first = fs
            .put_conditional(&path, b"one", None, None, CasCondition::IfNotExists)
            .await
            .unwrap();

        assert!(fs
            .put_conditional(&path, b"again", None, None, CasCondition::IfNotExists)
            .await
            .is_err());

        let second = fs
            .put_conditional(
                &path,
                b"two",
                None,
                None,
                CasCondition::IfMatch(first.clone()),
            )
            .await
            .unwrap();
        assert_ne!(first, second);

        assert!(fs
            .put_conditional(&path, b"stale", None, None, CasCondition::IfMatch(first))
            .await
            .is_err());

        let (bytes, tag) = fs.load_with_tag(&path).await.unwrap().unwrap();
        assert_eq!(bytes, b"two");
        assert_eq!(tag, second);

        let _ = fs.remove(&path).await;
        let _ = fs.remove(&Path::from_opfs_path("cas").unwrap()).await;
    }
}