use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use std::path::Path;
use tempfile::TempDir;
use parquet::data_type::Int32Type;
use parquet::file::properties::WriterProperties;
use parquet::file::writer::SerializedFileWriter;
use parquet::schema::parser::parse_message_type;
fn parxcli_cmd() -> Command {
Command::new(assert_cmd::cargo::cargo_bin!("parx"))
}
fn write_simple_parquet(path: &Path) -> parquet::errors::Result<()> {
let message_type = "message schema { REQUIRED INT32 id; }";
let schema = std::sync::Arc::new(parse_message_type(message_type)?);
let file = fs::File::create(path)?;
let props = std::sync::Arc::new(WriterProperties::builder().build());
let mut writer = SerializedFileWriter::new(file, schema, props)?;
let mut row_group_writer = writer.next_row_group()?;
if let Some(mut col_writer) = row_group_writer.next_column()? {
let values = [1i32, 2, 3];
col_writer
.typed::<Int32Type>()
.write_batch(&values, None, None)?;
col_writer.close()?;
}
row_group_writer.close()?;
writer.close()?;
Ok(())
}
#[test]
fn cli_build_inspect_verify_roundtrip() {
let temp_dir = TempDir::new().expect("temp dir");
let parquet_path = temp_dir.path().join("data.parquet");
write_simple_parquet(&parquet_path).expect("write parquet");
let parquet_str = parquet_path.to_str().unwrap();
parxcli_cmd()
.args(["build", parquet_str])
.assert()
.success();
let parx_path = format!("{}.parx", parquet_str);
assert!(Path::new(&parx_path).exists());
parxcli_cmd()
.args(["inspect", &parx_path])
.assert()
.success()
.stdout(predicate::str::contains("PARX File"));
parxcli_cmd()
.args(["verify", &parx_path, "--with-source"])
.assert()
.success()
.stdout(predicate::str::contains("Verification passed"));
}
#[test]
fn cli_build_with_compression() {
let temp_dir = TempDir::new().expect("temp dir");
let parquet_path = temp_dir.path().join("data.parquet");
write_simple_parquet(&parquet_path).expect("write parquet");
let parquet_str = parquet_path.to_str().unwrap();
let output_path = temp_dir.path().join("data.parquet.zstd.parx");
let output_str = output_path.to_str().unwrap();
parxcli_cmd()
.args(["build", parquet_str, "--compress", "zstd", "-o", output_str])
.assert()
.success();
parxcli_cmd()
.args(["inspect", output_str])
.assert()
.success()
.stdout(predicate::str::contains("Footer compressed"));
}
#[test]
fn cli_bundle_flow() {
let temp_dir = TempDir::new().expect("temp dir");
let parquet_path = temp_dir.path().join("data.parquet");
write_simple_parquet(&parquet_path).expect("write parquet");
let dir_str = temp_dir.path().to_str().unwrap();
parxcli_cmd()
.args(["bundle", "build", dir_str])
.assert()
.success();
let bundle_path = temp_dir.path().join("_parx_bundle.parx");
assert!(bundle_path.exists());
parxcli_cmd()
.args(["bundle", "inspect", bundle_path.to_str().unwrap()])
.assert()
.success();
parxcli_cmd()
.args([
"bundle",
"verify",
bundle_path.to_str().unwrap(),
"--with-sources",
])
.assert()
.success();
let extract_dir = temp_dir.path().join("extracted");
fs::create_dir_all(&extract_dir).unwrap();
parxcli_cmd()
.args([
"bundle",
"extract",
bundle_path.to_str().unwrap(),
"-o",
extract_dir.to_str().unwrap(),
])
.assert()
.success();
let extracted_parx = extract_dir.join("data.parquet.parx");
assert!(extracted_parx.exists());
}