use std::path::PathBuf;
use clap::{Args, Subcommand};
use super::AnalysisPreset;
pub const DEFAULT_PACKET_DIR: &str = "sensors/tokmd";
pub const DEFAULT_PACKET_CONTEXT_BUDGET: &str = "64000";
#[derive(Args, Debug, Clone)]
pub struct PacketArgs {
#[command(subcommand)]
pub command: PacketCommand,
}
#[derive(Subcommand, Debug, Clone)]
pub enum PacketCommand {
Generate(PacketGenerateArgs),
}
#[derive(Args, Debug, Clone)]
#[command(
after_help = "Examples:\n tokmd packet generate --base origin/main --head HEAD src/runtime/api\n tokmd packet generate --preset bun-ub --out sensors/tokmd --no-syntax src/runtime/api/MarkdownObject.rs"
)]
pub struct PacketGenerateArgs {
#[arg(long, value_enum, default_value_t = AnalysisPreset::BunUb)]
pub preset: AnalysisPreset,
#[arg(long, default_value = "origin/main")]
pub base: String,
#[arg(long, default_value = "HEAD")]
pub head: String,
#[arg(long = "out", value_name = "DIR", default_value = DEFAULT_PACKET_DIR)]
pub out: PathBuf,
#[arg(long, overrides_with = "no_syntax")]
pub syntax: bool,
#[arg(long = "no-syntax", overrides_with = "syntax")]
pub no_syntax: bool,
#[arg(long = "context-budget", default_value = DEFAULT_PACKET_CONTEXT_BUDGET)]
pub context_budget: String,
#[arg(value_name = "PATH", required = true)]
pub paths: Vec<PathBuf>,
}
impl PacketGenerateArgs {
pub fn want_syntax(&self) -> bool {
!self.no_syntax
}
}
#[cfg(test)]
mod tests {
use clap::Parser;
use super::*;
use crate::cli::parser::{Cli, Commands};
fn parse_generate(args: &[&str]) -> PacketGenerateArgs {
let mut argv = vec!["tokmd", "packet", "generate"];
argv.extend_from_slice(args);
let cli = Cli::try_parse_from(argv).unwrap();
match cli.command.unwrap() {
Commands::Packet(packet) => match packet.command {
PacketCommand::Generate(args) => args,
},
other => panic!("unexpected command: {other:?}"),
}
}
#[test]
fn generate_defaults_match_evidence_packet_contract() {
let args = parse_generate(&["src/runtime/api"]);
assert_eq!(args.preset, AnalysisPreset::BunUb);
assert_eq!(args.base, "origin/main");
assert_eq!(args.head, "HEAD");
assert_eq!(args.out, PathBuf::from(DEFAULT_PACKET_DIR));
assert_eq!(args.context_budget, DEFAULT_PACKET_CONTEXT_BUDGET);
assert_eq!(args.paths, vec![PathBuf::from("src/runtime/api")]);
assert!(args.want_syntax());
}
#[test]
fn generate_no_syntax_disables_syntax() {
let args = parse_generate(&["--no-syntax", "src/runtime/api"]);
assert!(!args.want_syntax());
}
#[test]
fn generate_explicit_syntax_keeps_syntax() {
let args = parse_generate(&["--syntax", "src/runtime/api"]);
assert!(args.want_syntax());
}
#[test]
fn generate_requires_paths() {
assert!(Cli::try_parse_from(["tokmd", "packet", "generate"]).is_err());
}
}