chore(release): prepare public source release
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "tonl"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
readme.workspace = true
|
||||
publish.workspace = true
|
||||
description = "Encode, decode, query, validate, index, stream, and ETL JSON-backed TONL data."
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
common = { path = "../common", default-features = false }
|
||||
lexopt.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd.workspace = true
|
||||
predicates.workspace = true
|
||||
tempfile.workspace = true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
//! Binary entry point for the `tonl` command.
|
||||
|
||||
fn main() {
|
||||
std::process::exit(tonl::main_entry());
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
//! Integration tests for the `tonl` command.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use assert_cmd::Command;
|
||||
use predicates::prelude::*;
|
||||
use serde_json::Value;
|
||||
use tempfile::tempdir;
|
||||
|
||||
fn fixture(path: &str) -> PathBuf {
|
||||
let fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("..")
|
||||
.join("..")
|
||||
.join("fixtures")
|
||||
.join("json-family")
|
||||
.join("tonl")
|
||||
.join(path);
|
||||
assert!(
|
||||
fixture.exists(),
|
||||
"missing fixture `{path}` at {}",
|
||||
fixture.display()
|
||||
);
|
||||
fixture
|
||||
}
|
||||
|
||||
fn cargo_tonl() -> Command {
|
||||
Command::cargo_bin("tonl").expect("binary")
|
||||
}
|
||||
|
||||
fn fixture_text(path: &str) -> String {
|
||||
fs::read_to_string(fixture(path)).expect("fixture text")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_json_object_through_tonl() {
|
||||
let encoded = cargo_tonl()
|
||||
.args(["encode"])
|
||||
.arg(fixture("sample.json"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("name = \"Ada\""))
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
|
||||
let decoded = cargo_tonl()
|
||||
.args(["decode"])
|
||||
.write_stdin(encoded)
|
||||
.assert()
|
||||
.success()
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
|
||||
let expected: Value =
|
||||
serde_json::from_str(&fixture_text("sample.json")).expect("expected json");
|
||||
let actual: Value = serde_json::from_slice(&decoded).expect("decoded json");
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_input_reports_line_diagnostics() {
|
||||
cargo_tonl()
|
||||
.args(["decode"])
|
||||
.arg(fixture("invalid.tonl"))
|
||||
.assert()
|
||||
.failure()
|
||||
.code(2)
|
||||
.stderr(predicate::str::contains("line 3"))
|
||||
.stderr(predicate::str::contains("valid JSON value"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supports_path_and_stdin_input() {
|
||||
cargo_tonl()
|
||||
.args(["decode"])
|
||||
.arg(fixture("sample.tonl"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"name\":\"Ada\""));
|
||||
|
||||
cargo_tonl()
|
||||
.args(["encode"])
|
||||
.write_stdin(fixture_text("sample.json"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("score = 42"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_json_wrapper_reports_tonl_text() {
|
||||
cargo_tonl()
|
||||
.args(["encode", "--json"])
|
||||
.arg(fixture("sample.json"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"format\":\"tonl\""))
|
||||
.stdout(predicate::str::contains("\"records\":1"))
|
||||
.stdout(predicate::str::contains("name = \\\"Ada\\\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_toon_wrapper_reports_tonl_text() {
|
||||
cargo_tonl()
|
||||
.args(["encode", "--format", "toon"])
|
||||
.arg(fixture("sample.json"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("format: tonl"))
|
||||
.stdout(predicate::str::contains("records: 1"))
|
||||
.stdout(predicate::str::contains("name = \\\"Ada\\\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn query_filters_records_by_field_value() {
|
||||
let output = cargo_tonl()
|
||||
.args(["query", "--where", "active=true"])
|
||||
.arg(fixture("records.tonl"))
|
||||
.assert()
|
||||
.success()
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
|
||||
let record: Value = serde_json::from_slice(&output).unwrap_or_else(|error| {
|
||||
panic!(
|
||||
"query output should be a JSON record: {error}\n{}",
|
||||
String::from_utf8_lossy(&output)
|
||||
)
|
||||
});
|
||||
assert_eq!(
|
||||
record["id"],
|
||||
"user-1",
|
||||
"stdout={}",
|
||||
String::from_utf8_lossy(&output)
|
||||
);
|
||||
assert_eq!(
|
||||
record["active"],
|
||||
true,
|
||||
"stdout={}",
|
||||
String::from_utf8_lossy(&output)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_reports_failures() {
|
||||
cargo_tonl()
|
||||
.args(["validate"])
|
||||
.arg(fixture("invalid.tonl"))
|
||||
.assert()
|
||||
.failure()
|
||||
.code(2)
|
||||
.stderr(predicate::str::contains("invalid TONL"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn index_build_and_query_lookup_record() {
|
||||
let temp = tempdir().expect("tempdir");
|
||||
let index = temp.path().join("records.tonl-index.json");
|
||||
|
||||
cargo_tonl()
|
||||
.args(["index", "build", "--key", "id", "--output"])
|
||||
.arg(&index)
|
||||
.arg(fixture("records.tonl"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("indexed 2 records"));
|
||||
|
||||
cargo_tonl()
|
||||
.args(["index", "query"])
|
||||
.arg(&index)
|
||||
.arg("user-2")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"name\":\"Bob\""))
|
||||
.stdout(predicate::str::contains("\"active\":false"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_query_smoke_filters_jsonl_records() {
|
||||
cargo_tonl()
|
||||
.args(["stream", "query", "--where", "active=false"])
|
||||
.arg(fixture("records.jsonl"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"id\":\"user-2\""))
|
||||
.stdout(predicate::str::contains("\"id\":\"user-1\"").not());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn etl_converts_jsonl_to_tonl_and_tonl_to_jsonl() {
|
||||
cargo_tonl()
|
||||
.args(["etl", "--from", "jsonl", "--to", "tonl"])
|
||||
.arg(fixture("records.jsonl"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("---"))
|
||||
.stdout(predicate::str::contains("id = \"user-1\""));
|
||||
|
||||
cargo_tonl()
|
||||
.args(["etl", "--from", "tonl", "--to", "jsonl"])
|
||||
.arg(fixture("records.tonl"))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("{\"id\":\"user-1\""))
|
||||
.stdout(predicate::str::contains("{\"id\":\"user-2\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn help_lists_full_tool_surface() {
|
||||
cargo_tonl()
|
||||
.arg("--help")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("encode"))
|
||||
.stdout(predicate::str::contains("decode"))
|
||||
.stdout(predicate::str::contains("query"))
|
||||
.stdout(predicate::str::contains("validate"))
|
||||
.stdout(predicate::str::contains("index build"))
|
||||
.stdout(predicate::str::contains("index query"))
|
||||
.stdout(predicate::str::contains("stream query"))
|
||||
.stdout(predicate::str::contains("etl"));
|
||||
}
|
||||
Reference in New Issue
Block a user