|
|
use super::*;
|
|
|
|
|
|
/// Shorthand to reduce boilerplate when creating [`Revision`] for testing
|
|
|
macro_rules! R {
|
|
|
($revision:literal) => {
|
|
|
Revision($revision)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/// Unit tests for:
|
|
|
///
|
|
|
/// ```ignore
|
|
|
/// fn compare_value(
|
|
|
/// current_merge: Revision,
|
|
|
/// merge_case_for_dest: impl Fn() -> MergeCase,
|
|
|
/// src_minor: &CopySource,
|
|
|
/// src_major: &CopySource,
|
|
|
/// ) -> (MergePick, /* overwrite: */ bool)
|
|
|
/// ```
|
|
|
#[test]
|
|
|
fn test_compare_value() {
|
|
|
// The `compare_value!` macro calls the `compare_value` function with
|
|
|
// arguments given in pseudo-syntax:
|
|
|
//
|
|
|
// * For `merge_case_for_dest` it takes a plain `MergeCase` value instead
|
|
|
// of a closure.
|
|
|
// * `CopySource` values are represented as `(rev, path, overwritten)`
|
|
|
// tuples of type `(Revision, Option<PathToken>, OrdSet<Revision>)`.
|
|
|
// * `PathToken` is an integer not read by `compare_value`. It only checks
|
|
|
// for `Some(_)` indicating a file copy v.s. `None` for a file deletion.
|
|
|
// * `OrdSet<Revision>` is represented as a Python-like set literal.
|
|
|
|
|
|
use MergeCase::*;
|
|
|
use MergePick::*;
|
|
|
|
|
|
assert_eq!(
|
|
|
compare_value!(
|
|
|
R!(1),
|
|
|
Normal,
|
|
|
(R!(1), None, { R!(1) }),
|
|
|
(R!(1), None, { R!(1) })
|
|
|
),
|
|
|
(Any, false)
|
|
|
);
|
|
|
}
|
|
|
|
|
|
/// Unit tests for:
|
|
|
///
|
|
|
/// ```ignore
|
|
|
/// fn merge_copies_dict(
|
|
|
/// path_map: &TwoWayPathMap, // Not visible in test cases
|
|
|
/// current_merge: Revision,
|
|
|
/// minor: InternalPathCopies,
|
|
|
/// major: InternalPathCopies,
|
|
|
/// get_merge_case: impl Fn(&HgPath) -> MergeCase + Copy,
|
|
|
/// ) -> InternalPathCopies
|
|
|
/// ```
|
|
|
#[test]
|
|
|
fn test_merge_copies_dict() {
|
|
|
// The `merge_copies_dict!` macro calls the `merge_copies_dict` function
|
|
|
// with arguments given in pseudo-syntax:
|
|
|
//
|
|
|
// * `TwoWayPathMap` and path tokenization are implicitly taken care of.
|
|
|
// All paths are given as string literals.
|
|
|
// * Key-value maps are represented with `{key1 => value1, key2 => value2}`
|
|
|
// pseudo-syntax.
|
|
|
// * `InternalPathCopies` is a map of copy destination path keys to
|
|
|
// `CopySource` values.
|
|
|
// - `CopySource` is represented as a `(rev, source_path, overwritten)`
|
|
|
// tuple of type `(Revision, Option<Path>, OrdSet<Revision>)`.
|
|
|
// - Unlike in `test_compare_value`, source paths are string literals.
|
|
|
// - `OrdSet<Revision>` is again represented as a Python-like set
|
|
|
// literal.
|
|
|
// * `get_merge_case` is represented as a map of copy destination path to
|
|
|
// `MergeCase`. The default for paths not in the map is
|
|
|
// `MergeCase::Normal`.
|
|
|
//
|
|
|
// `internal_path_copies!` creates an `InternalPathCopies` value with the
|
|
|
// same pseudo-syntax as in `merge_copies_dict!`.
|
|
|
|
|
|
use MergeCase::*;
|
|
|
|
|
|
assert_eq!(
|
|
|
merge_copies_dict!(
|
|
|
R!(1),
|
|
|
{"foo" => (R!(1), None, {})},
|
|
|
{},
|
|
|
{"foo" => Merged}
|
|
|
),
|
|
|
internal_path_copies!("foo" => (R!(1), None, {}))
|
|
|
);
|
|
|
}
|
|
|
|
|
|
/// Unit tests for:
|
|
|
///
|
|
|
/// ```ignore
|
|
|
/// impl CombineChangesetCopies {
|
|
|
/// fn new(children_count: HashMap<Revision, usize>) -> Self
|
|
|
///
|
|
|
/// // Called repeatedly:
|
|
|
/// fn add_revision_inner<'a>(
|
|
|
/// &mut self,
|
|
|
/// rev: Revision,
|
|
|
/// p1: Revision,
|
|
|
/// p2: Revision,
|
|
|
/// copy_actions: impl Iterator<Item = Action<'a>>,
|
|
|
/// get_merge_case: impl Fn(&HgPath) -> MergeCase + Copy,
|
|
|
/// )
|
|
|
///
|
|
|
/// fn finish(mut self, target_rev: Revision) -> PathCopies
|
|
|
/// }
|
|
|
/// ```
|
|
|
#[test]
|
|
|
fn test_combine_changeset_copies() {
|
|
|
// `combine_changeset_copies!` creates a `CombineChangesetCopies` with
|
|
|
// `new`, then calls `add_revision_inner` repeatedly, then calls `finish`
|
|
|
// for its return value.
|
|
|
//
|
|
|
// All paths given as string literals.
|
|
|
//
|
|
|
// * Key-value maps are represented with `{key1 => value1, key2 => value2}`
|
|
|
// pseudo-syntax.
|
|
|
// * `children_count` is a map of revision numbers to count of children in
|
|
|
// the DAG. It includes all revisions that should be considered by the
|
|
|
// algorithm.
|
|
|
// * Calls to `add_revision_inner` are represented as an array of anonymous
|
|
|
// structs with named fields, one pseudo-struct per call.
|
|
|
//
|
|
|
// `path_copies!` creates a `PathCopies` value, a map of copy destination
|
|
|
// keys to copy source values. Note: the arrows for map literal syntax
|
|
|
// point **backwards** compared to the logical direction of copy!
|
|
|
|
|
|
use crate::revlog::NULL_REVISION as NULL;
|
|
|
use Action::*;
|
|
|
use MergeCase::*;
|
|
|
|
|
|
assert_eq!(
|
|
|
combine_changeset_copies!(
|
|
|
{ R!(1) => 1, R!(2) => 1 },
|
|
|
[
|
|
|
{
|
|
|
rev: R!(1),
|
|
|
p1: NULL,
|
|
|
p2: NULL,
|
|
|
actions: [],
|
|
|
merge_cases: {},
|
|
|
},
|
|
|
{
|
|
|
rev: R!(2),
|
|
|
p1: NULL,
|
|
|
p2: NULL,
|
|
|
actions: [],
|
|
|
merge_cases: {},
|
|
|
},
|
|
|
{
|
|
|
rev: R!(3), p1: R!(1), p2: R!(2),
|
|
|
actions: [CopiedFromP1("destination.txt", "source.txt")],
|
|
|
merge_cases: {"destination.txt" => Merged},
|
|
|
},
|
|
|
],
|
|
|
R!(3),
|
|
|
),
|
|
|
path_copies!("destination.txt" => "source.txt")
|
|
|
);
|
|
|
}
|
|
|
|