Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions crates/tokmd/tests/cli_parser_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,16 @@ const PARSER_SUBCOMMANDS: &[&str] = &[
"evidence-packet",
];

const ENUMS_TO_FUZZ: &[&str] = &["--config", "--format", "--children", "--redact"];

fn parser_subcommands() -> impl Strategy<Value = &'static str> {
prop::sample::select(PARSER_SUBCOMMANDS.to_vec())
}

fn config_keys() -> impl Strategy<Value = &'static str> {
prop::sample::select(ENUMS_TO_FUZZ.to_vec())
}

#[test]
fn parser_subcommand_property_list_matches_clap_surface() {
let command = Cli::command();
Expand Down Expand Up @@ -72,4 +78,203 @@ proptest! {
iter_args.extend(args);
let _ = Cli::try_parse_from(iter_args);
}

#[test]
fn cli_parser_never_panics_on_enum_values(
subcmd in parser_subcommands(),
key in config_keys(),
val in "\\PC{0,20}",
args in prop::collection::vec("\\PC{0,30}", 0..10)
) {
let mut iter_args = vec![
"tokmd".to_string(),
subcmd.to_string(),
key.to_string(),
val
];
iter_args.extend(args);
let _ = Cli::try_parse_from(iter_args);
}
}

#[test]
fn config_resolve_fuzz() {
use tokmd::ResolvedConfig;
use tokmd::cli::CliLangArgs;
use tokmd::resolve_lang_with_config;
use tokmd_settings::{Profile, ViewProfile};

proptest!(|(
cli_top in prop::option::of(0..1000u64),
view_top in prop::option::of(0..1000u64),
prof_top in prop::option::of(0..1000u64),
cli_files in any::<bool>(),
view_files in prop::option::of(any::<bool>()),
prof_files in prop::option::of(any::<bool>()),
)| {
let cli = CliLangArgs {
format: None,
top: cli_top.map(|t| t as usize),
files: cli_files,
paths: None,
children: None,
};

let view = ViewProfile {
top: view_top.map(|t| t as usize),
format: None,
files: view_files,
children: None,
..Default::default()
};

let profile = Profile {
top: prof_top.map(|t| t as usize),
format: None,
files: prof_files,
children: None,
..Default::default()
};

let config = ResolvedConfig {
toml_view: Some(&view),
json_profile: Some(&profile),
toml: None,
};

let resolved = resolve_lang_with_config(&cli, &config);

let expected_top = cli_top.map(|t| t as usize)
.or(view_top.map(|t| t as usize))
.or(prof_top.map(|t| t as usize))
.unwrap_or(0);

assert_eq!(resolved.top, expected_top);

// Logical OR priority: CLI, then View, then Profile
// If CLI is true, it's true.
// If CLI is false, we check View.
// If View is Some(true), it's true.
// If View is Some(false), it's false (it shadows Profile).
// If View is None, we check Profile.
// If Profile is Some(true), it's true.
// If Profile is Some(false) or None, it's false.
let expected_files = if cli_files {
true
} else if let Some(v) = view_files {
v
} else if let Some(p) = prof_files {
p
} else {
false
};
assert_eq!(resolved.files, expected_files);
});
}

#[test]
fn config_resolve_fuzz_export() {
use tokmd::ResolvedConfig;
use tokmd::cli::CliExportArgs;
use tokmd::resolve_export_with_config;
use tokmd_settings::{ExportConfig, TomlConfig};

proptest!(|(
cli_min in prop::option::of(0..1000u64),
toml_min in prop::option::of(0..1000u64),
cli_max in prop::option::of(0..1000u64),
toml_max in prop::option::of(0..1000u64),
)| {
let cli = CliExportArgs {
format: None,
min_code: cli_min.map(|t| t as usize),
max_rows: cli_max.map(|t| t as usize),
paths: None,
output: None,
module_roots: None,
module_depth: None,
children: None,
redact: None,
meta: None,
strip_prefix: None,
};

let toml = TomlConfig {
export: ExportConfig {
min_code: toml_min.map(|t| t as usize),
max_rows: toml_max.map(|t| t as usize),
..Default::default()
},
..Default::default()
};

let config = ResolvedConfig {
toml_view: None,
json_profile: None,
toml: Some(&toml),
};

let resolved = resolve_export_with_config(&cli, &config);

let expected_min = cli_min.map(|t| t as usize)
.or(toml_min.map(|t| t as usize))
.unwrap_or(0);

assert_eq!(resolved.min_code, expected_min);

let expected_max = cli_max.map(|t| t as usize)
.or(toml_max.map(|t| t as usize))
.unwrap_or(0);

assert_eq!(resolved.max_rows, expected_max);
});
}

#[test]
fn config_resolve_fuzz_module() {
use tokmd::ResolvedConfig;
use tokmd::cli::CliModuleArgs;
use tokmd::resolve_module_with_config;
use tokmd_settings::{ModuleConfig, TomlConfig};

proptest!(|(
cli_depth in prop::option::of(0..20u8),
toml_depth in prop::option::of(0..20u8),
cli_top in prop::option::of(0..1000u64),

)| {
let cli = CliModuleArgs {
format: None,
top: cli_top.map(|t| t as usize),
module_depth: cli_depth.map(|d| d as usize),
paths: None,
module_roots: None,
children: None,
};

let toml = TomlConfig {
module: ModuleConfig {
depth: toml_depth.map(|d| d as usize),
..Default::default()
},
..Default::default()
};

// Note: the original `resolve_module_with_config` currently seems to not pick up
// `top` from the view/profile directly via the `TomlConfig` without a `ViewProfile`.
// We will just test the depth here which is in the `ModuleConfig`.
let config = ResolvedConfig {
toml_view: None,
json_profile: None,
toml: Some(&toml),
};

let resolved = resolve_module_with_config(&cli, &config);

let expected_depth = cli_depth.map(|d| d as usize)
.or(toml_depth.map(|d| d as usize))
.unwrap_or(2); // 2 is the default fallback

assert_eq!(resolved.module_depth, expected_depth);
Comment on lines +274 to +278

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In config_resolve_fuzz_module, cli_top is generated by the proptest strategy and passed to CliModuleArgs, but its resolved value is never asserted. Adding an assertion for resolved.top ensures that the fallback logic for top is also verified in this test case.

        let expected_depth = cli_depth.map(|d| d as usize)
            .or(toml_depth.map(|d| d as usize))
            .unwrap_or(2); // 2 is the default fallback

        assert_eq!(resolved.module_depth, expected_depth);

        let expected_top = cli_top.map(|t| t as usize).unwrap_or(0);
        assert_eq!(resolved.top, expected_top);

});
}
34 changes: 0 additions & 34 deletions fixtures/syntax/python/native_boundary.py

This file was deleted.

15 changes: 0 additions & 15 deletions fixtures/syntax/typescript/component.tsx

This file was deleted.

30 changes: 0 additions & 30 deletions fixtures/syntax/typescript/native_boundary.ts

This file was deleted.

41 changes: 0 additions & 41 deletions scripts/check-no-bare-self-hosted.sh

This file was deleted.

Loading