serde-jsonlines 0.7.0

Read & write JSON Lines documents
Documentation
#![cfg(feature = "async")]
mod common;
use crate::common::*;
use assert_fs::assert::PathAssert;
use assert_fs::NamedTempFile;
use futures_util::{stream::empty, SinkExt};
use serde_jsonlines::AsyncJsonLinesWriter;
use std::io::SeekFrom;
use std::pin::Pin;
use tokio::fs::File;
use tokio::io::{AsyncSeekExt, AsyncWriteExt};

#[tokio::test]
async fn test_write_one() {
    let tmpfile = NamedTempFile::new("test.jsonl").unwrap();
    {
        let fp = File::create(&tmpfile).await.unwrap();
        let mut writer = AsyncJsonLinesWriter::new(fp);
        writer
            .write(&Structure {
                name: "Foo Bar".into(),
                size: 42,
                on: true,
            })
            .await
            .unwrap();
        writer.flush().await.unwrap();
    }
    tmpfile.assert("{\"name\":\"Foo Bar\",\"size\":42,\"on\":true}\n");
}

#[tokio::test]
async fn test_write_two() {
    let tmpfile = NamedTempFile::new("test.jsonl").unwrap();
    {
        let fp = File::create(&tmpfile).await.unwrap();
        let mut writer = AsyncJsonLinesWriter::new(fp);
        writer
            .write(&Structure {
                name: "Foo Bar".into(),
                size: 42,
                on: true,
            })
            .await
            .unwrap();
        writer.write(&Point { x: 69, y: 105 }).await.unwrap();
        writer.flush().await.unwrap();
    }
    tmpfile.assert("{\"name\":\"Foo Bar\",\"size\":42,\"on\":true}\n{\"x\":69,\"y\":105}\n");
}

#[tokio::test]
async fn test_write_one_then_write_inner() {
    let tmpfile = NamedTempFile::new("test.jsonl").unwrap();
    {
        let fp = File::create(&tmpfile).await.unwrap();
        let mut writer = AsyncJsonLinesWriter::new(fp);
        writer
            .write(&Structure {
                name: "Foo Bar".into(),
                size: 42,
                on: true,
            })
            .await
            .unwrap();
        writer.flush().await.unwrap();
        let mut fp: File = writer.into_inner();
        fp.write_all(b"Not JSON\n").await.unwrap();
        fp.flush().await.unwrap();
    }
    tmpfile.assert("{\"name\":\"Foo Bar\",\"size\":42,\"on\":true}\nNot JSON\n");
}

#[tokio::test]
async fn test_write_one_then_write_pin_mut() {
    let tmpfile = NamedTempFile::new("test.jsonl").unwrap();
    {
        let fp = File::create(&tmpfile).await.unwrap();
        let mut writer = AsyncJsonLinesWriter::new(fp);
        writer
            .write(&Structure {
                name: "Foo Bar".into(),
                size: 42,
                on: true,
            })
            .await
            .unwrap();
        writer.flush().await.unwrap();
        tokio::pin!(writer);
        let mut fp: Pin<&mut File> = writer.get_pin_mut();
        fp.write_all(b"Not JSON\n").await.unwrap();
        fp.flush().await.unwrap();
    }
    tmpfile.assert("{\"name\":\"Foo Bar\",\"size\":42,\"on\":true}\nNot JSON\n");
}

#[tokio::test]
async fn test_write_then_back_up_then_write() {
    let tmpfile = NamedTempFile::new("test.jsonl").unwrap();
    {
        let fp = File::create(&tmpfile).await.unwrap();
        let mut writer = AsyncJsonLinesWriter::new(fp);
        writer
            .write(&Structure {
                name: "Foo Bar".into(),
                size: 42,
                on: true,
            })
            .await
            .unwrap();
        writer.flush().await.unwrap();
        let fp: &mut File = writer.get_mut();
        fp.seek(SeekFrom::Start(0)).await.unwrap();
        writer
            .write(&Structure {
                name: "Gnusto Cleesh".into(),
                size: 17,
                on: true,
            })
            .await
            .unwrap();
        writer.flush().await.unwrap();
    }
    tmpfile.assert("{\"name\":\"Gnusto Cleesh\",\"size\":17,\"on\":true}\n");
}

#[tokio::test]
async fn test_into_sink() {
    let tmpfile = NamedTempFile::new("test.jsonl").unwrap();
    {
        let fp = File::create(&tmpfile).await.unwrap();
        let mut sink = AsyncJsonLinesWriter::new(fp).into_sink();
        for item in [
            Structure {
                name: "Foo Bar".into(),
                size: 42,
                on: true,
            },
            Structure {
                name: "Quux".into(),
                size: 23,
                on: false,
            },
            Structure {
                name: "Gnusto Cleesh".into(),
                size: 17,
                on: true,
            },
        ] {
            sink.send(item).await.unwrap();
        }
        sink.close().await.unwrap();
    }
    tmpfile.assert(concat!(
        "{\"name\":\"Foo Bar\",\"size\":42,\"on\":true}\n",
        "{\"name\":\"Quux\",\"size\":23,\"on\":false}\n",
        "{\"name\":\"Gnusto Cleesh\",\"size\":17,\"on\":true}\n",
    ));
}

#[tokio::test]
async fn test_into_sink_send_none() {
    let tmpfile = NamedTempFile::new("test.jsonl").unwrap();
    {
        let fp = File::create(&tmpfile).await.unwrap();
        let mut sink = AsyncJsonLinesWriter::new(fp).into_sink();
        let mut stream = empty::<std::io::Result<Structure>>();
        sink.send_all(&mut stream).await.unwrap();
        sink.close().await.unwrap();
    }
    tmpfile.assert("");
}

#[tokio::test]
async fn test_feed_into_sink() {
    let tmpfile = NamedTempFile::new("test.jsonl").unwrap();
    {
        let fp = File::create(&tmpfile).await.unwrap();
        let mut sink = AsyncJsonLinesWriter::new(fp).into_sink();
        for item in [
            Structure {
                name: "Foo Bar".into(),
                size: 42,
                on: true,
            },
            Structure {
                name: "Quux".into(),
                size: 23,
                on: false,
            },
            Structure {
                name: "Gnusto Cleesh".into(),
                size: 17,
                on: true,
            },
        ] {
            sink.feed(item).await.unwrap();
        }
        sink.close().await.unwrap();
    }
    tmpfile.assert(concat!(
        "{\"name\":\"Foo Bar\",\"size\":42,\"on\":true}\n",
        "{\"name\":\"Quux\",\"size\":23,\"on\":false}\n",
        "{\"name\":\"Gnusto Cleesh\",\"size\":17,\"on\":true}\n",
    ));
}