Something went wrong. Try again.
Juju is a git/jj interface for the Helix editor
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124;; Copyright (C) 2026 Tom Waddington;;;; This program is free software: you can redistribute it and/or modify;; it under the terms of the GNU Affero General Public License as published by;; the Free Software Foundation, either version 3 of the License, or;; (at your option) any later version.
;;; test-diff-split.scm - side-by-side pairing of a hunk's lines;;;;;; Run in file mode from the repo root: steel tests/test-diff-split.scm;;; Requires the steel-test package in ~/.steel/cogs.
(require "steel-test/test.scm")(require "../src/model.scm")(require "../src/diff.scm")(require "../src/diff-split.scm")
;; A hunk from a diff body, so the tests read as the diff they describe.(define (hunk-of old-start new-start text) (car (parse-unified-diff (string-append "@@ -" (number->string old-start) ",9 +" (number->string new-start) ",9 @@\n" text))))
(define (rows-of old-start new-start text) (split-hunk-rows (hunk-of old-start new-start text)))
;; Compact row shape for comparison: (kind left-line left-text right-line;; right-text), with #f for an absent side.(define (shape r) (append (list (split-row-kind r)) (side-shape (split-row-left r)) (side-shape (split-row-right r))))
(define (side-shape s) (if s (list (split-side-line s) (split-side-text s)) (list #f #f)))
(define BALANCED (rows-of 10 10 "-old one\n-old two\n+new one\n+new two\n"))
(deftest balanced-change (is (= 2 (length BALANCED)) "two deletions and two additions pair up") (is (= '(change 10 "old one" 10 "new one") (shape (list-ref BALANCED 0)))) (is (= '(change 11 "old two" 11 "new two") (shape (list-ref BALANCED 1)))))
(deftest surplus-deletions (let ([rs (rows-of 5 5 "-a\n-b\n-c\n+x\n")]) (is (= 3 (length rs))) (is (= '(change 5 "a" 5 "x") (shape (list-ref rs 0)))) (testing "the surplus deletions are left-only, and only old advances" (is (= '(del 6 "b" #f #f) (shape (list-ref rs 1)))) (is (= '(del 7 "c" #f #f) (shape (list-ref rs 2)))))))
(deftest surplus-additions (let ([rs (rows-of 5 5 "-a\n+x\n+y\n+z\n")]) (is (= 3 (length rs))) (is (= '(change 5 "a" 5 "x") (shape (list-ref rs 0)))) (testing "the surplus additions are right-only, and only new advances" (is (= '(add #f #f 6 "y") (shape (list-ref rs 1)))) (is (= '(add #f #f 7 "z") (shape (list-ref rs 2)))))))
(deftest pure-runs (testing "additions with no deletion before them" (let ([rs (rows-of 3 3 "+one\n+two\n")]) (is (= '(add #f #f 3 "one") (shape (car rs)))) (is (= '(add #f #f 4 "two") (shape (list-ref rs 1)))))) (testing "deletions with no addition after them" (let ([rs (rows-of 3 3 "-one\n-two\n")]) (is (= '(del 3 "one" #f #f) (shape (car rs)))) (is (= '(del 4 "two" #f #f) (shape (list-ref rs 1)))))))
;; Old and new start at different numbers when an earlier hunk changed the;; line count; each side must count in its own file.(define SURROUNDED (rows-of 20 24 " keep\n-gone\n+here\n ctx\n"))
(deftest context-and-numbering (is (= 3 (length SURROUNDED))) (testing "a context line fills both sides at their own numbers" (is (= '(context 20 "keep" 24 "keep") (shape (list-ref SURROUNDED 0)))) (is (= '(context 22 "ctx" 26 "ctx") (shape (list-ref SURROUNDED 2))))) (is (= '(change 21 "gone" 25 "here") (shape (list-ref SURROUNDED 1)))))
(deftest single-line-hunk (let ([rs (rows-of 1 1 " only\n")]) (is (= 1 (length rs))) (is (= '(context 1 "only" 1 "only") (shape (car rs))))))
(deftest empty-hunk (is (= '() (split-hunk-rows (make-hunk "@@ -0,0 +0,0 @@" (cons 0 0) (cons 0 0) '())))))
(deftest no-newline-marker (let ([rs (rows-of 1 1 "-a\n+b\n\\ No newline at end of file\n")]) (is (= 2 (length rs)) "the marker gets a row of its own") (is (= 'change (split-row-kind (car rs)))) (testing "it belongs to neither file, so it has no line number or right side" (is (= 'meta (split-row-kind (list-ref rs 1)))) (is (= #f (split-side-line (split-row-left (list-ref rs 1))))) (is (= #f (split-row-right (list-ref rs 1)))))))
;; The index is the line's position in `hunk-lines`, which is what a partial;; staging patch selects on.(deftest body-indices (let ([rs (rows-of 1 1 " ctx\n-a\n-b\n+x\n")]) (testing "context lines are not stageable" (is (= #f (split-side-index (split-row-left (list-ref rs 0))))) (is (= #f (split-side-index (split-row-right (list-ref rs 0)))))) (testing "a change row points at both its deletion and its addition" (is (= 1 (split-side-index (split-row-left (list-ref rs 1))))) (is (= 3 (split-side-index (split-row-right (list-ref rs 1)))))) (testing "the surplus deletion keeps its own index" (is (= 2 (split-side-index (split-row-left (list-ref rs 2))))))))
;; Two runs in one hunk: the second must resume from where the first stopped.(deftest consecutive-runs (let ([rs (rows-of 1 1 "-a\n+x\n ctx\n-b\n+y\n")]) (is (= 3 (length rs))) (is (= '(change 1 "a" 1 "x") (shape (list-ref rs 0)))) (is (= '(context 2 "ctx" 2 "ctx") (shape (list-ref rs 1)))) (is (= '(change 3 "b" 3 "y") (shape (list-ref rs 2)))) (is (= 3 (split-side-index (split-row-left (list-ref rs 2)))) "index resumes") (is (= 4 (split-side-index (split-row-right (list-ref rs 2)))))))
(run-tests!)