quinjet 0.0.48

A fast, live, keyboard-first Git source-control interface for the terminal
use super::*;

#[test]
fn parses_every_conversation_shape_the_query_can_emit() {
    let output = b"comment\toctocat\t2026-08-01T10:00:00Z\t\tLooks good to me\\nship it\thttps://example.test/c/1\t\t\n\
review\treviewer\t2026-08-01T11:00:00Z\tAPPROVED\t\thttps://example.test/r/1\t99\t\n\
review_comment\treviewer\t2026-08-01T11:00:01Z\tsrc/main.rs:42\tExtract this\thttps://example.test/rc/1\t99\t@@ -1 +1 @@\n\
commit\tAda\t2026-08-01T12:00:00Z\tabc1234\tAdd the thing\thttps://example.test/commit\tabc1234567890\t\n\
force_push\toctocat\t2026-08-01T13:00:00Z\t\t\t\tdeadbeef\t\n\
renamed\toctocat\t2026-08-01T14:00:00Z\tOld title\t\t\tNew title\t\n\
weird_new_event\tsomebody\t2026-08-01T15:00:00Z\t\t\t\t\t\n";

    let entries = parse_conversation(output).unwrap();

    assert_eq!(entries.len(), 7);
    assert_eq!(entries[0].kind, ConversationKind::Comment);
    assert_eq!(entries[0].body, "Looks good to me\nship it");
    assert_eq!(entries[1].kind, ConversationKind::Review);
    assert_eq!(entries[1].detail, "APPROVED");
    assert_eq!(entries[2].kind, ConversationKind::ReviewComment);
    assert_eq!(entries[2].detail, "src/main.rs:42");
    assert_eq!(entries[2].context, "@@ -1 +1 @@");
    assert_eq!(entries[3].kind, ConversationKind::Commit);
    assert_eq!(entries[3].reference, "abc1234567890");
    assert_eq!(entries[4].kind, ConversationKind::ForcePush);
    assert_eq!(entries[4].reference, "deadbeef");
    assert_eq!(entries[5].kind, ConversationKind::Renamed);
    assert_eq!(
        (entries[5].detail.as_str(), entries[5].reference.as_str()),
        ("Old title", "New title")
    );
    assert_eq!(
        entries[6].kind,
        ConversationKind::Other,
        "an event GitHub adds later still renders with its actor and time"
    );
    assert_eq!(entries[6].actor, "somebody");
}

#[test]
fn rejects_records_that_do_not_match_the_query_shape() {
    parse_conversation(b"comment\tonly\ttwo\n").unwrap_err();
}

#[test]
fn queries_are_page_bounded_and_scoped_to_the_pull_request() {
    let request = super::super::tests::pull_request(
        super::super::tests::repository(
            "acme/widget",
            "https://github.com/acme/widget",
            &["origin"],
        ),
        42,
    );

    assert_eq!(
        timeline_endpoint(&request),
        "repos/acme/widget/issues/42/timeline?per_page=100"
    );
    assert_eq!(
        review_comment_endpoint(&request),
        "repos/acme/widget/pulls/42/comments?per_page=100&sort=created&direction=desc"
    );
    assert!(timeline_tsv_jq().contains("head_ref_force_pushed"));
    assert!(timeline_tsv_jq().contains("line-commented"));
    assert!(REVIEW_COMMENT_TSV_JQ.contains("diff_hunk"));
}

#[test]
fn cache_entries_remember_whether_the_read_was_complete() {
    let complete = conversation_cache_entry(true, b"comment\trow\n");
    let partial = conversation_cache_entry(false, b"comment\trow\n");

    assert_eq!(
        split_conversation_cache(&complete),
        (true, b"comment\trow\n".as_slice())
    );
    assert_eq!(
        split_conversation_cache(&partial),
        (false, b"comment\trow\n".as_slice())
    );
}

#[test]
fn appended_records_always_end_on_a_record_boundary() {
    let mut collected = Vec::new();
    let mut lines = 0;
    append_records(&mut collected, &mut lines, b"a\tb\nc\td");
    append_records(&mut collected, &mut lines, b"e\tf\n");

    assert_eq!(lines, 3, "an unterminated tail still counts as one record");
    assert_eq!(collected, b"a\tb\nc\td\ne\tf\n");
}