Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/dissimilar/src/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 16 kB image not shown  

Quelle  tests.rs

  Sprache: Rust
 

#![allow(
    clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257
)]

use super::*;
use std::sync::OnceLock;

macro_rules! range {
    ($text:expr) => {{
        static CHARS: OnceLock<Vec<char>> = OnceLock::new();
        let chars = CHARS.get_or_init(|| $text.chars().collect());
        Range::new(chars, ..)
    }};
}

macro_rules! diff_list {
    () => {
        Solution {
            text1: Range::empty(),
            text2: Range::empty(),
            diffs: Vec::new(),
        }
    };
    ($($kind:ident($text:literal)),+ $(,)?) => {{
        #[allow(unused_macro_rules)]
        macro_rules! text1 {
            (Insert, $s:literal) => { "" };
            (Delete, $s:literal) => { $s };
            (Equal, $s:literal) => { $s };
        }
        #[allow(unused_macro_rules)]
        macro_rules! text2 {
            (Insert, $s:literal) => { $s };
            (Delete, $s:literal) => { "" };
            (Equal, $s:literal) => { $s };
        }
        let text1 = range!(concat!($(text1!($kind, $text)),*));
        let text2 = range!(concat!($(text2!($kind, $text)),*));
        let (_i, _j) = (&mut 0, &mut 0);
        #[allow(unused_macro_rules)]
        macro_rules! range {
            (Insert, $s:literal) => {
                Diff::Insert(range(text2.doc, _j, $s))
            };
            (Delete, $s:literal) => {
                Diff::Delete(range(text1.doc, _i, $s))
            };
            (Equal, $s:literal) => {
                Diff::Equal(range(text1.doc, _i, $s), range(text2.doc, _j, $s))
            };
        }
        Solution {
            text1,
            text2,
            diffs: vec![$(range!($kind, $text)),*],
        }
    }};
}

fn range<'a>(doc: &'a [char], offset: &mut usize, text: &str) -> Range<'a> {
    let len = text.chars().count();
    let range = Range {
        doc,
        offset: *offset,
        len,
    };
    *offset += len;
    range
}

macro_rules! assert_diffs {
    ([$($kind:ident($text:literal)),* $(,)?], $solution:ident, $msg:expr $(,)?) => {
        let expected = &[$(Chunk::$kind($text)),*];
        assert!(
            same_diffs(expected, &$solution.diffs),
            concat!($msg, "\nexpected={:#?}\nactual={:#?}"),
            expected, $solution.diffs,
        );
    };
}

fn same_diffs(expected: &[Chunk], actual: &[Diff]) -> bool {
    fn eq(expected: &str, actual: &Range) -> bool {
        expected.chars().eq(slice(*actual).iter().copied())
    }

    expected.len() == actual.len()
        && expected.iter().zip(actual).all(|pair| match pair {
            (Chunk::Insert(expected), Diff::Insert(actual)) => eq(expected, actual),
            (Chunk::Delete(expected), Diff::Delete(actual)) => eq(expected, actual),
            (Chunk::Equal(expected), Diff::Equal(actual1, actual2)) => {
                eq(expected, actual1) && eq(expected, actual2)
            }
            (_, _) => false,
        })
}

#[test]
fn test_common_prefix() {
    let text1 = range!("abc");
    let text2 = range!("xyz");
    assert_eq!(0, common_prefix(text1, text2), "Null case");

    let text1 = range!("1234abcdef");
    let text2 = range!("1234xyz");
    assert_eq!(4, common_prefix(text1, text2), "Non-null case");

    let text1 = range!("1234");
    let text2 = range!("1234xyz");
    assert_eq!(4, common_prefix(text1, text2), "Whole case");
}

#[test]
fn test_common_suffix() {
    let text1 = range!("abc");
    let text2 = range!("xyz");
    assert_eq!(0, common_suffix(text1, text2), "Null case");

    let text1 = range!("abcdef1234");
    let text2 = range!("xyz1234");
    assert_eq!(4, common_suffix(text1, text2), "Non-null case");

    let text1 = range!("1234");
    let text2 = range!("xyz1234");
    assert_eq!(4, common_suffix(text1, text2), "Whole case");
}

#[test]
fn test_common_overlap() {
    let text1 = Range::empty();
    let text2 = range!("abcd");
    assert_eq!(0, common_overlap(text1, text2), "Null case");

    let text1 = range!("abc");
    let text2 = range!("abcd");
    assert_eq!(3, common_overlap(text1, text2), "Whole case");

    let text1 = range!("123456");
    let text2 = range!("abcd");
    assert_eq!(0, common_overlap(text1, text2), "No overlap");

    let text1 = range!("123456xxx");
    let text2 = range!("xxxabcd");
    assert_eq!(3, common_overlap(text1, text2), "Overlap");

    // Some overly clever languages (C#) may treat ligatures as equal to their
    // component letters. E.g. U+FB01 == 'fi'
    let text1 = range!("fi");
    let text2 = range!("\u{fb01}i");
    assert_eq!(0, common_overlap(text1, text2), "Unicode");
}

#[test]
fn test_cleanup_merge() {
    let mut solution = diff_list![];
    cleanup_merge(&mut solution);
    assert_diffs!([], solution, "Null case");

    let mut solution = diff_list![Equal("a"), Delete("b"), Insert("c")];
    cleanup_merge(&mut solution);
    assert_diffs!(
        [Equal("a"), Delete("b"), Insert("c")],
        solution,
        "No change case",
    );

    let mut solution = diff_list![Equal("a"), Equal("b"), Equal("c")];
    cleanup_merge(&mut solution);
    assert_diffs!([Equal("abc")], solution, "Merge equalities");

    let mut solution = diff_list![Delete("a"), Delete("b"), Delete("c")];
    cleanup_merge(&mut solution);
    assert_diffs!([Delete("abc")], solution, "Merge deletions");

    let mut solution = diff_list![Insert("a"), Insert("b"), Insert("c")];
    cleanup_merge(&mut solution);
    assert_diffs!([Insert("abc")], solution, "Merge insertions");

    let mut solution = diff_list![
        Delete("a"),
        Insert("b"),
        Delete("c"),
        Insert("d"),
        Equal("e"),
        Equal("f"),
    ];
    cleanup_merge(&mut solution);
    assert_diffs!(
        [Delete("ac"), Insert("bd"), Equal("ef")],
        solution,
        "Merge interweave",
    );

    let mut solution = diff_list![Delete("a"), Insert("abc"), Delete("dc")];
    cleanup_merge(&mut solution);
    assert_diffs!(
        [Equal("a"), Delete("d"), Insert("b"), Equal("c")],
        solution,
        "Prefix and suffix detection",
    );

    let mut solution = diff_list![
        Equal("x"),
        Delete("a"),
        Insert("abc"),
        Delete("dc"),
        Equal("y"),
    ];
    cleanup_merge(&mut solution);
    assert_diffs!(
        [Equal("xa"), Delete("d"), Insert("b"), Equal("cy")],
        solution,
        "Prefix and suffix detection with equalities",
    );

    let mut solution = diff_list![Equal("a"), Insert("ba"), Equal("c")];
    cleanup_merge(&mut solution);
    assert_diffs!([Insert("ab"), Equal("ac")], solution, "Slide edit left");

    let mut solution = diff_list![Equal("c"), Insert("ab"), Equal("a")];
    cleanup_merge(&mut solution);
    assert_diffs!([Equal("ca"), Insert("ba")], solution, "Slide edit right");

    let mut solution = diff_list![
        Equal("a"),
        Delete("b"),
        Equal("c"),
        Delete("ac"),
        Equal("x"),
    ];
    cleanup_merge(&mut solution);
    assert_diffs!(
        [Delete("abc"), Equal("acx")],
        solution,
        "Slide edit left recursive",
    );

    let mut solution = diff_list![
        Equal("x"),
        Delete("ca"),
        Equal("c"),
        Delete("b"),
        Equal("a"),
    ];
    cleanup_merge(&mut solution);
    assert_diffs!(
        [Equal("xca"), Delete("cba")],
        solution,
        "Slide edit right recursive",
    );

    let mut solution = diff_list![Delete("b"), Insert("ab"), Equal("c")];
    cleanup_merge(&mut solution);
    assert_diffs!([Insert("a"), Equal("bc")], solution, "Empty range");

    let mut solution = diff_list![Equal(""), Insert("a"), Equal("b")];
    cleanup_merge(&mut solution);
    assert_diffs!([Insert("a"), Equal("b")], solution, "Empty equality");
}

#[test]
fn test_cleanup_semantic_lossless() {
    let mut solution = diff_list![];
    cleanup_semantic_lossless(&mut solution);
    assert_diffs!([], solution, "Null case");

    let mut solution = diff_list![
        Equal("AAA\r\n\r\nBBB"),
        Insert("\r\nDDD\r\n\r\nBBB"),
        Equal("\r\nEEE"),
    ];
    cleanup_semantic_lossless(&mut solution);
    assert_diffs!(
        [
            Equal("AAA\r\n\r\n"),
            Insert("BBB\r\nDDD\r\n\r\n"),
            Equal("BBB\r\nEEE"),
        ],
        solution,
        "Blank lines",
    );

    let mut solution = diff_list![Equal("AAA\r\nBBB"), Insert(" DDD\r\nBBB"), Equal(" EEE")];
    cleanup_semantic_lossless(&mut solution);
    assert_diffs!(
        [Equal("AAA\r\n"), Insert("BBB DDD\r\n"), Equal("BBB EEE")],
        solution,
        "Line boundaries",
    );

    let mut solution = diff_list![Equal("The c"), Insert("ow and the c"), Equal("at.")];
    cleanup_semantic_lossless(&mut solution);
    assert_diffs!(
        [Equal("The "), Insert("cow and the "), Equal("cat.")],
        solution,
        "Word boundaries",
    );

    let mut solution = diff_list![Equal("The-c"), Insert("ow-and-the-c"), Equal("at.")];
    cleanup_semantic_lossless(&mut solution);
    assert_diffs!(
        [Equal("The-"), Insert("cow-and-the-"), Equal("cat.")],
        solution,
        "Alphanumeric boundaries",
    );

    let mut solution = diff_list![Equal("a"), Delete("a"), Equal("ax")];
    cleanup_semantic_lossless(&mut solution);
    assert_diffs!([Delete("a"), Equal("aax")], solution, "Hitting the start");

    let mut solution = diff_list![Equal("xa"), Delete("a"), Equal("a")];
    cleanup_semantic_lossless(&mut solution);
    assert_diffs!([Equal("xaa"), Delete("a")], solution, "Hitting the end");

    let mut solution = diff_list![Equal("The xxx. The "), Insert("zzz. The "), Equal("yyy.")];
    cleanup_semantic_lossless(&mut solution);
    assert_diffs!(
        [Equal("The xxx."), Insert(" The zzz."), Equal(" The yyy.")],
        solution,
        "Sentence boundaries",
    );
}

#[test]
fn test_cleanup_semantic() {
    let mut solution = diff_list![];
    cleanup_semantic(&mut solution);
    assert_diffs!([], solution, "Null case");

    let mut solution = diff_list![Delete("ab"), Insert("cd"), Equal("12"), Delete("e")];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [Delete("ab"), Insert("cd"), Equal("12"), Delete("e")],
        solution,
        "No elimination #1",
    );

    let mut solution = diff_list![Delete("abc"), Insert("ABC"), Equal("1234"), Delete("wxyz")];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [Delete("abc"), Insert("ABC"), Equal("1234"), Delete("wxyz")],
        solution,
        "No elimination #2",
    );

    let mut solution = diff_list![Delete("a"), Equal("b"), Delete("c")];
    cleanup_semantic(&mut solution);
    assert_diffs!([Delete("abc"), Insert("b")], solution, "Simple elimination",);

    let mut solution = diff_list![
        Delete("ab"),
        Equal("cd"),
        Delete("e"),
        Equal("f"),
        Insert("g"),
    ];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [Delete("abcdef"), Insert("cdfg")],
        solution,
        "Backpass elimination",
    );

    let mut solution = diff_list![
        Insert("1"),
        Equal("A"),
        Delete("B"),
        Insert("2"),
        Equal("_"),
        Insert("1"),
        Equal("A"),
        Delete("B"),
        Insert("2"),
    ];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [Delete("AB_AB"), Insert("1A2_1A2")],
        solution,
        "Multiple elimination",
    );

    let mut solution = diff_list![Equal("The c"), Delete("ow and the c"), Equal("at.")];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [Equal("The "), Delete("cow and the "), Equal("cat.")],
        solution,
        "Word boundaries",
    );

    let mut solution = diff_list![Delete("abcxx"), Insert("xxdef")];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [Delete("abcxx"), Insert("xxdef")],
        solution,
        "No overlap elimination",
    );

    let mut solution = diff_list![Delete("abcxxx"), Insert("xxxdef")];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [Delete("abc"), Equal("xxx"), Insert("def")],
        solution,
        "Overlap elimination",
    );

    let mut solution = diff_list![Delete("xxxabc"), Insert("defxxx")];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [Insert("def"), Equal("xxx"), Delete("abc")],
        solution,
        "Reverse overlap elimination",
    );

    let mut solution = diff_list![
        Delete("abcd1212"),
        Insert("1212efghi"),
        Equal("----"),
        Delete("A3"),
        Insert("3BC"),
    ];
    cleanup_semantic(&mut solution);
    assert_diffs!(
        [
            Delete("abcd"),
            Equal("1212"),
            Insert("efghi"),
            Equal("----"),
            Delete("A"),
            Equal("3"),
            Insert("BC"),
        ],
        solution,
        "Two overlap eliminations",
    );
}

#[test]
fn test_bisect() {
    let text1 = range!("cat");
    let text2 = range!("map");
    let solution = Solution {
        text1,
        text2,
        diffs: bisect(text1, text2),
    };
    assert_diffs!(
        [
            Delete("c"),
            Insert("m"),
            Equal("a"),
            Delete("t"),
            Insert("p"),
        ],
        solution,
        "Normal",
    );
}

#[test]
fn test_main() {
    let solution = main(Range::empty(), Range::empty());
    assert_diffs!([], solution, "Null case");

    let solution = main(range!("abc"), range!("abc"));
    assert_diffs!([Equal("abc")], solution, "Equality");

    let solution = main(range!("abc"), range!("ab123c"));
    assert_diffs!(
        [Equal("ab"), Insert("123"), Equal("c")],
        solution,
        "Simple insertion",
    );

    let solution = main(range!("a123bc"), range!("abc"));
    assert_diffs!(
        [Equal("a"), Delete("123"), Equal("bc")],
        solution,
        "Simple deletion",
    );

    let solution = main(range!("abc"), range!("a123b456c"));
    assert_diffs!(
        [
            Equal("a"),
            Insert("123"),
            Equal("b"),
            Insert("456"),
            Equal("c"),
        ],
        solution,
        "Two insertions",
    );

    let solution = main(range!("a123b456c"), range!("abc"));
    assert_diffs!(
        [
            Equal("a"),
            Delete("123"),
            Equal("b"),
            Delete("456"),
            Equal("c"),
        ],
        solution,
        "Two deletions",
    );

    let solution = main(range!("a"), range!("b"));
    assert_diffs!([Delete("a"), Insert("b")], solution, "Simple case #1");

    let solution = main(
        range!("Apples are a fruit."),
        range!("Bananas are also fruit."),
    );
    assert_diffs!(
        [
            Delete("Apple"),
            Insert("Banana"),
            Equal("s are a"),
            Insert("lso"),
            Equal(" fruit."),
        ],
        solution,
        "Simple case #2",
    );

    let solution = main(range!("ax\t"), range!("\u{0680}x\000"));
    assert_diffs!(
        [
            Delete("a"),
            Insert("\u{0680}"),
            Equal("x"),
            Delete("\t"),
            Insert("\000"),
        ],
        solution,
        "Simple case #3",
    );

    let solution = main(range!("1ayb2"), range!("abxab"));
    assert_diffs!(
        [
            Delete("1"),
            Equal("a"),
            Delete("y"),
            Equal("b"),
            Delete("2"),
            Insert("xab"),
        ],
        solution,
        "Overlap #1",
    );

    let solution = main(range!("abcy"), range!("xaxcxabc"));
    assert_diffs!(
        [Insert("xaxcx"), Equal("abc"), Delete("y")],
        solution,
        "Overlap #2",
    );

    let solution = main(
        range!("ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg"),
        range!("a-bcd-efghijklmnopqrs"),
    );
    assert_diffs!(
        [
            Delete("ABCD"),
            Equal("a"),
            Delete("="),
            Insert("-"),
            Equal("bcd"),
            Delete("="),
            Insert("-"),
            Equal("efghijklmnopqrs"),
            Delete("EFGHIJKLMNOefg"),
        ],
        solution,
        "Overlap #3",
    );

    let solution = main(
        range!("a [[Pennsylvania]] and [[New"),
        range!(" and [[Pennsylvania]]"),
    );
    assert_diffs!(
        [
            Insert(" "),
            Equal("a"),
            Insert("nd"),
            Equal(" [[Pennsylvania]]"),
            Delete(" and [[New"),
        ],
        solution,
        "Large equality",
    );
}

Messung V0.5 in Prozent
C=90 H=97 G=93

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.