mirror of
https://github.com/rizsotto/Bear.git
synced 2026-05-28 00:20:45 +02:00
dea535751c
Option A: move free functions to methods on their natural types - FlagMatch::name_len() (was codegen::flag_name_len) - EnvEntry::validate() (was codegen::validate_env_entry) - EnvMappingYaml::to_rust() (was codegen::env_mapping_to_rust) codegen.rs now contains only the two string-to-string converters (pattern_to_rust, result_to_rust) that operate on raw YAML strings. Option B: introduce ResolvedTable struct that encapsulates inheritance resolution and code generation for a single compiler table. - ResolvedTable::new() merges flags, ignore_when, slash_prefix, env - ResolvedTable::generate() produces the complete output file - generate() in lib.rs becomes a thin loop over TABLES - Snapshot tests reduce from 20-line helper to one-liner Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
134 lines
4.4 KiB
Rust
134 lines
4.4 KiB
Rust
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
//! Property-based tests for pattern_to_rust and FlagMatch::name_len.
|
|
|
|
use bear_codegen::codegen::pattern_to_rust;
|
|
use bear_codegen::yaml_types::FlagMatch;
|
|
use proptest::prelude::*;
|
|
|
|
/// Strategy for generating flag name strings (e.g., "-I", "--std", "/Fo").
|
|
fn flag_name_strategy() -> impl Strategy<Value = String> {
|
|
prop::string::string_regex("-{1,2}[A-Za-z][A-Za-z0-9_-]{0,15}")
|
|
.unwrap()
|
|
.prop_filter("must not be empty after prefix", |s| s.len() > 1)
|
|
}
|
|
|
|
/// Strategy for generating optional count values.
|
|
fn count_strategy() -> impl Strategy<Value = Option<u32>> {
|
|
prop_oneof![Just(None), (0u32..10).prop_map(Some)]
|
|
}
|
|
|
|
/// Strategy for generating pattern suffixes.
|
|
fn suffix_strategy() -> impl Strategy<Value = &'static str> {
|
|
prop_oneof![Just(""), Just("*"), Just("=*"), Just(":*"), Just("{ }*"), Just("{=}*"), Just("{:}*"),]
|
|
}
|
|
|
|
// pattern_to_rust always produces output starting with "FlagPattern::".
|
|
proptest! {
|
|
#[test]
|
|
fn output_starts_with_flag_pattern(
|
|
flag in flag_name_strategy(),
|
|
suffix in suffix_strategy(),
|
|
count in count_strategy(),
|
|
) {
|
|
let pattern = format!("{}{}", flag, suffix);
|
|
let output = pattern_to_rust(&pattern, count);
|
|
prop_assert!(
|
|
output.starts_with("FlagPattern::"),
|
|
"Expected FlagPattern:: prefix, got: {}",
|
|
output
|
|
);
|
|
}
|
|
}
|
|
|
|
// pattern_to_rust maps each suffix to the expected variant.
|
|
proptest! {
|
|
#[test]
|
|
fn suffix_determines_variant(
|
|
flag in flag_name_strategy(),
|
|
count in count_strategy(),
|
|
) {
|
|
// { }* -> ExactlyWithGluedOrSep
|
|
let output = pattern_to_rust(&format!("{}{{ }}*", flag), count);
|
|
prop_assert!(output.contains("ExactlyWithGluedOrSep"), "{}", output);
|
|
|
|
// {=}* -> ExactlyWithEqOrSep
|
|
let output = pattern_to_rust(&format!("{}{{=}}*", flag), count);
|
|
prop_assert!(output.contains("ExactlyWithEqOrSep"), "{}", output);
|
|
|
|
// {:}* -> ExactlyWithColonOrSep
|
|
let output = pattern_to_rust(&format!("{}{{:}}*", flag), count);
|
|
prop_assert!(output.contains("ExactlyWithColonOrSep"), "{}", output);
|
|
|
|
// :* -> ExactlyWithColon
|
|
let output = pattern_to_rust(&format!("{}:*", flag), count);
|
|
prop_assert!(output.contains("ExactlyWithColon"), "{}", output);
|
|
}
|
|
}
|
|
|
|
// =* without count -> ExactlyWithEq; with count -> Prefix.
|
|
proptest! {
|
|
#[test]
|
|
fn eq_star_variant_depends_on_count(flag in flag_name_strategy()) {
|
|
let pattern = format!("{}=*", flag);
|
|
|
|
let without_count = pattern_to_rust(&pattern, None);
|
|
prop_assert!(without_count.contains("ExactlyWithEq"), "{}", without_count);
|
|
|
|
let with_count = pattern_to_rust(&pattern, Some(1));
|
|
prop_assert!(with_count.contains("Prefix"), "{}", with_count);
|
|
}
|
|
}
|
|
|
|
// Bare flag (no suffix) -> Exactly.
|
|
proptest! {
|
|
#[test]
|
|
fn bare_flag_produces_exactly(flag in flag_name_strategy(), count in count_strategy()) {
|
|
let output = pattern_to_rust(&flag, count);
|
|
prop_assert!(output.contains("Exactly("), "Expected Exactly, got: {}", output);
|
|
}
|
|
}
|
|
|
|
// flag* (star suffix, no separator) -> Prefix.
|
|
proptest! {
|
|
#[test]
|
|
fn star_suffix_produces_prefix(flag in flag_name_strategy(), count in count_strategy()) {
|
|
let pattern = format!("{}*", flag);
|
|
let output = pattern_to_rust(&pattern, count);
|
|
prop_assert!(output.contains("Prefix("), "Expected Prefix, got: {}", output);
|
|
}
|
|
}
|
|
|
|
// FlagMatch::name_len is always <= the pattern length.
|
|
proptest! {
|
|
#[test]
|
|
fn name_len_bounded_by_pattern(
|
|
flag in flag_name_strategy(),
|
|
suffix in suffix_strategy(),
|
|
count in count_strategy(),
|
|
) {
|
|
let pattern = format!("{}{}", flag, suffix);
|
|
let m = FlagMatch { pattern: pattern.clone(), count };
|
|
let len = m.name_len();
|
|
prop_assert!(
|
|
len <= pattern.len(),
|
|
"name_len({}) = {} > pattern.len() = {}",
|
|
pattern, len, pattern.len()
|
|
);
|
|
}
|
|
}
|
|
|
|
// FlagMatch::name_len is always > 0 for non-empty patterns.
|
|
proptest! {
|
|
#[test]
|
|
fn name_len_positive(
|
|
flag in flag_name_strategy(),
|
|
suffix in suffix_strategy(),
|
|
count in count_strategy(),
|
|
) {
|
|
let pattern = format!("{}{}", flag, suffix);
|
|
let m = FlagMatch { pattern, count };
|
|
prop_assert!(m.name_len() > 0);
|
|
}
|
|
}
|