kcode-k1-rust-code-document 0.1.0

Represent and chunk one authored K1 Rust code document
Documentation
use kcode_k1_rust_code_document::RustCodeDocument;
use kcode_k1_rust_package::{AuthorityId, LibraryFamily, LibraryId, SourceFile, SourcePackage};
use kcode_k1_transaction_id::TxId;
use semver::Version;
use std::ops::Range;

fn identity() -> LibraryId {
    let authority = AuthorityId::new(TxId::from_bytes([7; 12]));
    let family = LibraryFamily::new(authority, "demo").unwrap();
    LibraryId::new(family, Version::new(0, 1, 0)).unwrap()
}

fn default_manifest() -> String {
    RustCodeDocument::approved_default(identity())
        .unwrap()
        .manifest()
        .to_owned()
}

fn document_with_code(code: &str) -> RustCodeDocument {
    RustCodeDocument::new(
        identity(),
        "# Consumer contract\n",
        default_manifest(),
        code,
    )
    .unwrap()
}

fn ranges(code: &str) -> Vec<Range<usize>> {
    document_with_code(code).code_chunk_ranges()
}

fn whole(end: usize) -> Vec<Range<usize>> {
    std::iter::once(0..end).collect()
}

fn reconstruct(code: &str, ranges: &[Range<usize>]) -> String {
    ranges.iter().map(|range| &code[range.clone()]).collect()
}

#[test]
fn approved_default_is_exact_and_round_trips() {
    let document = RustCodeDocument::approved_default(identity()).unwrap();
    let expected_manifest = concat!(
        "[package]\n",
        "name = \"k1-070707070707070707070707-demo\"\n",
        "version = \"0.1.0\"\n",
        "edition = \"2024\"\n",
        "rust-version = \"1.97\"\n",
        "license = \"MIT\"\n",
        "autobins = false\n",
        "autoexamples = false\n",
        "autotests = false\n",
        "autobenches = false\n\n",
        "[lib]\n",
        "name = \"demo\"\n",
        "path = \"src/lib.rs\"\n\n",
        "[lints.rust]\n",
        "unsafe_code = \"forbid\"\n\n",
        "[workspace]\n",
        "resolver = \"3\"\n"
    );
    assert_eq!(
        document.documentation(),
        "# Consumer contract\n\n`run` performs no operation.\n"
    );
    assert_eq!(document.manifest(), expected_manifest);
    assert_eq!(document.code(), "pub fn run() {}\n");
    assert_eq!(document.identity(), &identity());
    let package = document.clone().into_source_package();
    let paths: Vec<&str> = package.files().iter().map(|file| file.path()).collect();
    assert_eq!(paths, ["Cargo.toml", "Documentation.md", "src/lib.rs"]);
    let recovered = RustCodeDocument::from_source_package(package.clone()).unwrap();
    assert_eq!(recovered.into_source_package(), package);
}

#[test]
fn shape_utf8_identity_and_targets_are_enforced() {
    let base = RustCodeDocument::approved_default(identity())
        .unwrap()
        .into_source_package();
    let mut extra = base.files().to_vec();
    extra.push(SourceFile::new("README.md", b"extra".to_vec()));
    let extra = SourcePackage::new(identity(), extra).unwrap();
    assert!(RustCodeDocument::from_source_package(extra).is_err());
    let missing: Vec<SourceFile> = base
        .files()
        .iter()
        .filter(|file| file.path() != "src/lib.rs")
        .cloned()
        .collect();
    let missing = SourcePackage::new(identity(), missing).unwrap();
    assert!(RustCodeDocument::from_source_package(missing).is_err());
    let mut non_utf: Vec<SourceFile> = base
        .files()
        .iter()
        .filter(|file| file.path() != "src/lib.rs")
        .cloned()
        .collect();
    non_utf.push(SourceFile::new("src/lib.rs", vec![0xff]));
    let non_utf = SourcePackage::new(identity(), non_utf).unwrap();
    assert!(RustCodeDocument::from_source_package(non_utf).is_err());
    let changed = default_manifest().replace(
        "k1-070707070707070707070707-demo",
        "k1-070707070707070707070707-other",
    );
    assert!(RustCodeDocument::new(identity(), "docs", changed, "code").is_err());
    let noncanonical =
        default_manifest().replace("license = \"MIT\"\n", "license = \"MIT\"\nauthors = []\n");
    assert!(RustCodeDocument::new(identity(), "docs", noncanonical, "code").is_err());
    let bin = format!(
        "{}\n[[bin]]\nname = \"tool\"\npath = \"src/lib.rs\"\n",
        default_manifest()
    );
    assert!(RustCodeDocument::new(identity(), "docs", bin, "code").is_err());
    let example = format!("{}\n[[example]]\nname = \"sample\"\n", default_manifest());
    assert!(RustCodeDocument::new(identity(), "docs", example, "code").is_err());
}

#[test]
fn dependency_forms_remain_supported() {
    let additions = concat!(
        "[dependencies]\n",
        "serde = \"1\"\n",
        "peer = { package = \"k1-090909090909090909090909-peer\", version = \"0.3\", registry = \"k1\" }\n\n",
        "[lints.rust]"
    );
    let manifest = default_manifest().replace("[lints.rust]", additions);
    let document =
        RustCodeDocument::new(identity(), "docs", manifest.clone(), "pub fn run() {}\n").unwrap();
    assert_eq!(document.manifest(), manifest);
    assert_eq!(
        document.clone().into_source_package().dependencies().len(),
        1
    );
    assert_eq!(
        RustCodeDocument::from_source_package(document.into_source_package())
            .unwrap()
            .manifest(),
        manifest
    );
}

#[test]
fn every_content_preserves_line_endings_bom_and_final_newline() {
    let documentation = "\u{feff}# Contract\r\n\r\nExact";
    let manifest = default_manifest().replace('\n', "\r\n");
    let code = "\u{feff}pub fn run() {\r\n}";
    let document =
        RustCodeDocument::new(identity(), documentation, manifest.clone(), code).unwrap();
    assert_eq!(document.documentation(), documentation);
    assert_eq!(document.manifest(), manifest);
    assert_eq!(document.code(), code);
    assert_eq!(reconstruct(code, &document.code_chunk_ranges()), code);
    let default = RustCodeDocument::approved_default(identity()).unwrap();
    assert!(default.documentation().ends_with('\n'));
    assert!(default.manifest().ends_with('\n'));
    assert!(default.code().ends_with('\n'));
}

#[test]
fn top_level_items_split_on_unicode_scalar_floor() {
    let first = format!("const FIRST: &str = r#\"{}\"#;", "é".repeat(810));
    let second = format!("const SECOND: &str = r#\"{}\"#;", "界".repeat(810));
    let code = format!("{first}\n{second}\n");
    let chunks = ranges(&code);
    assert_eq!(chunks.len(), 2);
    assert_eq!(chunks[0], 0..first.len());
    assert_eq!(reconstruct(&code, &chunks), code);
    assert!(
        chunks
            .iter()
            .all(|range| code[range.clone()].chars().count() >= 800)
    );
}

#[test]
fn direct_impl_and_trait_members_are_safe_points() {
    let text = "x".repeat(810);
    let code = format!(
        "struct Unit;\nimpl Unit {{\nfn one() -> &'static str {{ r#\"{text}\"# }}\nfn two() -> &'static str {{ r#\"{text}\"# }}\n}}\ntrait Work {{\nfn three() -> &'static str {{ r#\"{text}\"# }}\nfn four() -> &'static str {{ r#\"{text}\"# }}\n}}\n"
    );
    let chunks = ranges(&code);
    assert_eq!(chunks.len(), 4);
    assert_eq!(reconstruct(&code, &chunks), code);
    assert!(
        chunks
            .iter()
            .all(|range| code[range.clone()].chars().count() >= 800)
    );
}

#[test]
fn attributes_raw_strings_macros_comments_and_nesting_stay_indivisible() {
    let first = [
        "#[allow(dead_code)]\nfn complex() {\nlet raw = r###\"",
        &"}\"#/*".repeat(180),
        "\"###;\nmacro_rules! local { () => {{ raw.len() }}; }\nlet _ = local!();\n/* kept */\n}",
    ]
    .concat();
    let second = format!(
        "#[allow(dead_code)]\nfn second() {{ let _ = r#\"{}\"#; }}",
        "z".repeat(900)
    );
    let code = format!("{first} // trailing\r\n{second}");
    let chunks = ranges(&code);
    assert_eq!(chunks.len(), 2);
    assert_eq!(chunks[0], 0..first.len());
    assert_eq!(reconstruct(&code, &chunks), code);
}

#[test]
fn malformed_small_huge_and_short_tail_use_whole_file_fallbacks() {
    assert_eq!(ranges(""), whole(0));
    let small = "pub fn run() {}\n";
    assert_eq!(ranges(small), whole(small.len()));
    let malformed = format!("fn broken({}", "x".repeat(2000));
    assert_eq!(ranges(&malformed), whole(malformed.len()));
    let huge = format!("const ONLY: &str = r#\"{}\"#;", "q".repeat(5000));
    assert_eq!(ranges(&huge), whole(huge.len()));
    let first = format!("const FIRST: &str = r#\"{}\"#;", "a".repeat(900));
    let short_tail = format!("{first}\nconst T: u8 = 1;");
    assert_eq!(ranges(&short_tail), whole(short_tail.len()));
}