use std::path::Path;
use chrono::{TimeZone, Utc};
use git_workarea::{CommitId, GitContext, Identity, MergeStatus};
use log::{Level, LevelFilter, Log, Metadata, Record};
use crate::stager::{
CandidateTopic, IntegrationResult, InvalidCommitReason, OldTopicRemoval, StagedTopic, Stager,
StagerError, Topic, UnstageReason,
};
fn setup_logging() {
struct SimpleLogger;
impl Log for SimpleLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= Level::Debug
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
println!("[{}] {}", record.level(), record.args());
}
}
fn flush(&self) {}
}
static LOGGER: SimpleLogger = SimpleLogger;
let _ = log::set_logger(&LOGGER);
log::set_max_level(LevelFilter::Debug);
}
fn git_context() -> GitContext {
setup_logging();
let gitdir = concat!(env!("CARGO_MANIFEST_DIR"), "/.git");
let config = concat!(env!("CARGO_MANIFEST_DIR"), "/test/config");
GitContext::new_with_config(gitdir, config)
}
const BASE: &str = "3eee1bbaea3e4df5d23fa3731675568fc12c4429";
const STAGE: &str = "8d9ea0c2afb796d2439a4880344c1fa5f8925f8a";
const ADD_CONTENT: &str = "6c688206b267a2bc85de9797190c087f2419858f";
const ADD_CONTENT_MERGE: &str = "700429914a51d2629fb2658d109009f879b958fd";
const ADD_MORE_CONTENT: &str = "205d74e638808e411941193b24ae5cc472728cb6";
const ADD_MORE_CONTENT_MERGE: &str = "8d9ea0c2afb796d2439a4880344c1fa5f8925f8a";
const BLOB_HASH: &str = "1e7caa9ea89a3016bc73f03b5e4c167711a21374";
const STAGE_BAD_MESSAGE_SUBJECT: &str = "eb7d39b3dc3f7d3afb07856c80577a46f78de45a";
const STAGE_BAD_MESSAGE_NO_URL: &str = "7a1b0581e416e0d10ceebce2bcc5652611d243f8";
const STAGE_BAD_MESSAGE_NO_ID: &str = "0c40c51db76f3e05dbe3cf6d4eef4e16a94f0114";
const STAGE_ZERO_ID: &str = "ef1c82d798e8591ff2d93e4476042902620a8570";
const STAGE_OCTOPUS: &str = "1ec897890fad0503ecf8dd5b383911bc85a42727";
const STAGE_UNRELATED: &str = "6ddea91c270758e447ba2d598f22a21713f8d751";
const STAGE_EXTRA_TRAILER: &str = "865ea0a304b88641747e4268a3791440f3b82737";
const STAGE_UNPARSEABLE_ID: &str = "61d1ca65cc7d6e0e535407ef0ff573504a9ee5e0";
const STAGE_DUPLICATE: &str = "f48e3249e8a744c7615630bf1169255028a0f7f1";
const BASE_UPDATE: &str = "12d5e4eb5e85ced667bf384c5ef33098786894da";
const BASE_CONFLICT: &str = "b012aa62a489702c42e223ae7d05cd26db0edceb";
const ADD_CONTENT_UPDATE: &str = "912389b87aab2908359194669f9c27cf20c2ceab";
const ADD_CONTENT_REWRITE: &str = "6073dcbb13125cd9d613379c9d3c945febb02e12";
const ADD_CONTENT_CONFLICT: &str = "fe73844a5e0c816171679c60b5e8b82d934a7571";
fn stager_identity() -> Identity {
Identity::new("Git Topic Stage Test", "git-topic-stage@example.com")
}
fn topic_identity() -> Identity {
Identity::new("Ben Boeckel", "ben.boeckel@kitware.com")
}
fn new_topic(commit: &str, identity: &Identity, id: u64, name: &str, url: &str) -> Topic {
Topic::new(
CommitId::new(commit),
identity.clone(),
Utc::now(),
id,
name,
url,
)
}
fn content_topic(commit: &str) -> Topic {
new_topic(commit, &topic_identity(), 1, "add-content", "add-content")
}
fn more_content_topic(commit: &str) -> Topic {
new_topic(
commit,
&topic_identity(),
2,
"add-more-content",
"add-more-content",
)
}
fn check_topic_ignore_date(actual: &Topic, expected: &Topic) {
assert_eq!(&actual.commit, &expected.commit);
assert_eq!(&actual.author, &expected.author);
assert_eq!(&actual.id, &expected.id);
assert_eq!(&actual.name, &expected.name);
assert_eq!(&actual.url, &expected.url);
}
#[test]
fn test_base_branch() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stager = Stager::new(&ctx, base.clone());
assert_eq!(stager.base(), &base);
assert_eq!(stager.topics().len(), 0);
assert_eq!(stager.head(), &base);
}
#[test]
fn test_stage_branch_empty() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(BASE);
let stager = Stager::from_branch(&ctx, base.clone(), stage).unwrap();
assert_eq!(stager.base(), &base);
assert_eq!(stager.topics().len(), 0);
assert_eq!(stager.head(), &base);
}
#[test]
fn test_stage_branch_non_commit() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(BLOB_HASH);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: 1e7caa9ea89a3016bc73f03b5e4c167711a21374: not a commit",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
assert_eq!(reason, InvalidCommitReason::NotACommit);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_not_related() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_UNRELATED);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: 6ddea91c270758e447ba2d598f22a21713f8d751: not related",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
assert_eq!(reason, InvalidCommitReason::NotRelated);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_no_exist() {
let ctx = git_context();
let stage_ref = "refs/stage/doesntexist";
ctx.git()
.arg("update-ref")
.arg("-d")
.arg(stage_ref)
.status()
.unwrap();
let base = CommitId::new(BASE);
let stage = CommitId::new(stage_ref);
let stager = Stager::from_branch(&ctx, base.clone(), stage).unwrap();
assert_eq!(stager.base(), &base);
assert_eq!(stager.topics().len(), 0);
assert_eq!(stager.head(), &base);
}
#[test]
fn test_stage_branch() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let stager = Stager::from_branch(&ctx, base.clone(), stage.clone()).unwrap();
assert_eq!(stager.base(), &base);
assert_eq!(stager.topics().len(), 2);
assert_eq!(stager.head(), &stage);
let topics = stager.topics();
assert_eq!(
topics[0],
StagedTopic {
merge: CommitId::new(ADD_CONTENT_MERGE),
topic: content_topic(ADD_CONTENT),
},
);
assert_eq!(topics[0].topic.author, topic_identity());
assert_eq!(
topics[0].topic.stamp,
Utc.with_ymd_and_hms(2016, 8, 1, 21, 28, 10).unwrap(),
);
assert_eq!(
topics[1],
StagedTopic {
merge: CommitId::new(ADD_MORE_CONTENT_MERGE),
topic: more_content_topic(ADD_MORE_CONTENT),
},
);
assert_eq!(topics[1].topic.author, topic_identity());
assert_eq!(
topics[1].topic.stamp,
Utc.with_ymd_and_hms(2016, 8, 1, 21, 28, 39).unwrap(),
);
}
#[test]
fn test_stage_clear() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let mut stager = Stager::from_branch(&ctx, base.clone(), stage.clone()).unwrap();
assert_eq!(stager.base(), &base);
assert_eq!(stager.topics().len(), 2);
assert_eq!(stager.head(), &stage);
let topics = stager.clear();
assert_eq!(stager.base(), &base);
assert_eq!(stager.topics().len(), 0);
assert_eq!(stager.head(), &base);
assert_eq!(
topics[0],
StagedTopic {
merge: CommitId::new(ADD_CONTENT_MERGE),
topic: content_topic(ADD_CONTENT),
},
);
assert_eq!(topics[0].topic.author, topic_identity());
assert_eq!(
topics[0].topic.stamp,
Utc.with_ymd_and_hms(2016, 8, 1, 21, 28, 10).unwrap(),
);
assert_eq!(
topics[1],
StagedTopic {
merge: CommitId::new(ADD_MORE_CONTENT_MERGE),
topic: more_content_topic(ADD_MORE_CONTENT),
},
);
assert_eq!(topics[1].topic.author, topic_identity());
assert_eq!(
topics[1].topic.stamp,
Utc.with_ymd_and_hms(2016, 8, 1, 21, 28, 39).unwrap(),
);
}
#[test]
fn test_stage_find_topic() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let stager = Stager::from_branch(&ctx, base, stage).unwrap();
let content_topic = content_topic(ADD_CONTENT);
let more_content_topic = more_content_topic(ADD_MORE_CONTENT);
assert_eq!(
stager.find_topic(&content_topic).unwrap(),
&StagedTopic {
merge: CommitId::new(ADD_CONTENT_MERGE),
topic: content_topic.clone(),
},
);
assert_eq!(
stager.find_topic_by_id(1).unwrap(),
&StagedTopic {
merge: CommitId::new(ADD_CONTENT_MERGE),
topic: content_topic,
},
);
assert_eq!(
stager.find_topic(&more_content_topic).unwrap(),
&StagedTopic {
merge: CommitId::new(ADD_MORE_CONTENT_MERGE),
topic: more_content_topic.clone(),
},
);
assert_eq!(
stager.find_topic_by_id(2).unwrap(),
&StagedTopic {
merge: CommitId::new(ADD_MORE_CONTENT_MERGE),
topic: more_content_topic,
},
);
assert_eq!(
stager.find_topic(&new_topic(BASE, &stager_identity(), 0, "base", "base")),
None,
);
assert_eq!(
stager.find_topic(&new_topic(
ADD_CONTENT_CONFLICT,
&topic_identity(),
1,
"add-content-conflict",
"add-content-conflict"
)),
None,
);
assert_eq!(
stager.find_topic(&new_topic(
ADD_CONTENT_MERGE,
&topic_identity(),
1,
"add-content-merge",
"add-content-merge"
)),
None,
);
assert_eq!(stager.find_topic_by_id(0), None);
}
#[test]
fn test_stage_branch_invalid_non_merge() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(ADD_CONTENT);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: 6c688206b267a2bc85de9797190c087f2419858f: non-merge commit",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
assert_eq!(reason, InvalidCommitReason::NonMergeCommit);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_invalid_merge_message_subject() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_BAD_MESSAGE_SUBJECT);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: eb7d39b3dc3f7d3afb07856c80577a46f78de45a: invalid subject",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
assert_eq!(
reason,
InvalidCommitReason::InvalidSubject(
"Merge branch 'tests/topic/add-content' into tests/base".into(),
),
);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_invalid_merge_message_no_url() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_BAD_MESSAGE_NO_URL);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: 7a1b0581e416e0d10ceebce2bcc5652611d243f8: missing url",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
assert_eq!(reason, InvalidCommitReason::MissingUrl);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_invalid_merge_message_no_id() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_BAD_MESSAGE_NO_ID);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: 0c40c51db76f3e05dbe3cf6d4eef4e16a94f0114: missing id",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
assert_eq!(reason, InvalidCommitReason::MissingId);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_unparseable_merge_id() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_UNPARSEABLE_ID);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: 61d1ca65cc7d6e0e535407ef0ff573504a9ee5e0: unparseable id",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
if let InvalidCommitReason::UnparseableId(parse_err) = reason {
assert_eq!(parse_err, "invalid digit found in string");
} else {
panic!("invalid commit reason: {:?}", reason);
}
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_invalid_merge_id() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_ZERO_ID);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: ef1c82d798e8591ff2d93e4476042902620a8570: invalid id (0)",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
assert_eq!(reason, InvalidCommitReason::ZeroId);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_invalid_octopus_merge() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_OCTOPUS);
let err = Stager::from_branch(&ctx, base, stage.clone()).unwrap_err();
assert_eq!(
err.to_string(),
"invalid integration branch: 1ec897890fad0503ecf8dd5b383911bc85a42727: octopus merge",
);
if let StagerError::InvalidIntegrationBranch {
commit,
reason,
} = err
{
assert_eq!(commit, stage);
assert_eq!(reason, InvalidCommitReason::OctopusMerge);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_branch_extra_trailer() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_EXTRA_TRAILER);
let stager = Stager::from_branch(&ctx, base.clone(), stage.clone()).unwrap();
assert_eq!(stager.base(), &base);
assert_eq!(stager.topics().len(), 1);
assert_eq!(stager.head(), &stage);
let topics = stager.topics();
assert_eq!(
topics[0],
StagedTopic {
merge: CommitId::new(STAGE_EXTRA_TRAILER),
topic: content_topic(ADD_CONTENT),
},
);
assert_eq!(topics[0].topic.author, topic_identity());
assert_eq!(
topics[0].topic.stamp,
Utc.with_ymd_and_hms(2016, 8, 1, 21, 28, 10).unwrap(),
);
}
#[test]
fn test_stage_branch_stale_stage() {
let ctx = git_context();
let base = CommitId::new(ADD_MORE_CONTENT);
let stage = CommitId::new(ADD_CONTENT_MERGE);
let stager = Stager::from_branch(&ctx, base, stage).unwrap();
let content_topic = content_topic(ADD_CONTENT);
assert_eq!(
stager.find_topic(&content_topic).unwrap(),
&StagedTopic {
merge: stager.head().clone(),
topic: content_topic.clone(),
},
);
assert_eq!(
stager.find_topic_by_id(1).unwrap(),
&StagedTopic {
merge: stager.head().clone(),
topic: content_topic,
},
);
}
#[test]
fn test_stage_unstage_tip() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let topic = more_content_topic(ADD_MORE_CONTENT);
let result = stager
.unstage(StagedTopic {
merge: CommitId::new(ADD_MORE_CONTENT_MERGE),
topic: topic.clone(),
})
.unwrap();
assert_eq!(result.results.len(), 0);
let old_topic = result.old_topic.as_ref().unwrap();
assert_eq!(old_topic.topic(), &topic);
if let OldTopicRemoval::Removed(ref st) = *old_topic {
assert_eq!(st.merge, CommitId::new(ADD_MORE_CONTENT_MERGE));
assert_eq!(st.topic, topic);
} else {
panic!("invalid unstaging reason: {:?}", result.old_topic);
}
}
#[test]
fn test_stage_unstage_mid() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let topic = content_topic(ADD_CONTENT);
let result = stager
.unstage(StagedTopic {
merge: CommitId::new(ADD_CONTENT_MERGE),
topic: topic.clone(),
})
.unwrap();
assert_eq!(result.results.len(), 1);
let iresult = &result.results[0];
assert!(iresult.on_stage());
let staged_topic = more_content_topic(ADD_MORE_CONTENT);
check_topic_ignore_date(iresult.topic(), &staged_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_MORE_CONTENT));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let old_topic = result.old_topic.as_ref().unwrap();
assert_eq!(old_topic.topic(), &topic);
if let OldTopicRemoval::Removed(ref st) = *old_topic {
assert_eq!(st.merge, CommitId::new(ADD_CONTENT_MERGE));
assert_eq!(st.topic, topic);
} else {
panic!("invalid unstaging reason: {:?}", result.old_topic);
}
}
#[test]
fn test_stage_unstage_base() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let result = stager.unstage(StagedTopic {
merge: CommitId::new(BASE),
topic: new_topic(BASE, &topic_identity(), 0, "base", "base"),
});
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.to_string(), "cannot unstage base");
if let StagerError::CannotUnstageBase = err {
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_stage_base_update() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let topic = new_topic(BASE, &stager_identity(), 0, "base", "base");
let candidate = CandidateTopic {
old_id: Some(topic.clone()),
new_id: new_topic(BASE_UPDATE, &topic_identity(), 0, "base", "base"),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let result = stager.stage(candidate).unwrap();
assert_eq!(result.results.len(), 2);
let iresult = &result.results[0];
assert!(iresult.on_stage());
let staged_topic = content_topic(ADD_CONTENT);
check_topic_ignore_date(iresult.topic(), &staged_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_CONTENT));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let iresult = &result.results[1];
assert!(iresult.on_stage());
let staged_topic = more_content_topic(ADD_MORE_CONTENT);
check_topic_ignore_date(iresult.topic(), &staged_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_MORE_CONTENT));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let old_topic = result.old_topic.as_ref().unwrap();
assert_eq!(old_topic.topic(), &topic);
if let OldTopicRemoval::Obsoleted {
ref old_merge,
ref replacement,
} = *old_topic
{
assert_eq!(
old_merge,
&StagedTopic {
merge: CommitId::new(BASE),
topic,
},
);
let replacement = replacement.as_ref().unwrap();
assert_eq!(replacement.commit(), &CommitId::new(BASE_UPDATE));
assert_eq!(&replacement.merge, &CommitId::new(BASE_UPDATE));
} else {
panic!("invalid unstaging reason: {:?}", result.old_topic);
}
}
#[test]
fn test_stage_stage_base_conflict() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let topic = new_topic(BASE, &stager_identity(), 0, "base", "base");
let candidate = CandidateTopic {
old_id: Some(topic.clone()),
new_id: new_topic(BASE_CONFLICT, &stager_identity(), 0, "base", "base"),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let result = stager.stage(candidate).unwrap();
assert_eq!(result.results.len(), 2);
let iresult = &result.results[0];
assert!(!iresult.on_stage());
let staged_topic = content_topic(ADD_CONTENT);
check_topic_ignore_date(iresult.topic(), &staged_topic);
if let IntegrationResult::Unstaged(ref t, ref reason) = *iresult {
assert_eq!(t.commit, CommitId::new(ADD_CONTENT));
format!("{:?}", *reason);
match *reason {
UnstageReason::MergeConflict(ref cs) => {
assert_eq!(cs.len(), 2);
assert_eq!(cs[0].path(), Path::new("content"));
assert_eq!(cs[1].path(), Path::new("content"));
},
}
} else {
panic!("invalid integration result: {:?}", iresult);
}
let iresult = &result.results[1];
assert!(iresult.on_stage());
let staged_topic = more_content_topic(ADD_MORE_CONTENT);
check_topic_ignore_date(iresult.topic(), &staged_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_MORE_CONTENT));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let old_topic = result.old_topic.as_ref().unwrap();
assert_eq!(old_topic.topic(), &topic);
if let OldTopicRemoval::Obsoleted {
ref old_merge,
ref replacement,
} = *old_topic
{
assert_eq!(
old_merge,
&StagedTopic {
merge: CommitId::new(BASE),
topic,
},
);
let replacement = replacement.as_ref().unwrap();
assert_eq!(replacement.commit(), &CommitId::new(BASE_CONFLICT));
assert_eq!(&replacement.merge, &CommitId::new(BASE_CONFLICT));
} else {
panic!("invalid unstaging reason: {:?}", result.old_topic);
}
}
#[test]
fn test_stage_stage_new_branch() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(BASE);
let topic = content_topic(ADD_CONTENT);
let candidate = CandidateTopic {
old_id: None,
new_id: topic.clone(),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let result = stager.stage(candidate).unwrap();
assert_eq!(result.results.len(), 1);
let iresult = &result.results[0];
assert!(iresult.on_stage());
check_topic_ignore_date(iresult.topic(), &topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_CONTENT));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
if result.old_topic.as_ref().is_none() {
} else {
panic!(
"unstaged an old topic for a new branch: {:?}",
result.old_topic,
);
}
}
#[test]
fn test_stage_stage_mid_update() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let topic = content_topic(ADD_CONTENT);
let update_topic = content_topic(ADD_CONTENT_UPDATE);
let candidate = CandidateTopic {
old_id: Some(topic.clone()),
new_id: update_topic.clone(),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let result = stager.stage(candidate).unwrap();
assert_eq!(result.results.len(), 2);
let iresult = &result.results[0];
assert!(iresult.on_stage());
let staged_topic = more_content_topic(ADD_MORE_CONTENT);
check_topic_ignore_date(iresult.topic(), &staged_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_MORE_CONTENT));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let iresult = &result.results[1];
assert!(iresult.on_stage());
check_topic_ignore_date(iresult.topic(), &update_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_CONTENT_UPDATE));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let old_topic = result.old_topic.as_ref().unwrap();
assert_eq!(old_topic.topic(), &topic);
if let OldTopicRemoval::Obsoleted {
ref old_merge,
ref replacement,
} = *old_topic
{
assert_eq!(
old_merge,
&StagedTopic {
merge: CommitId::new(ADD_CONTENT_MERGE),
topic,
},
);
let replacement = replacement.as_ref().unwrap();
assert_eq!(replacement.commit(), &CommitId::new(ADD_CONTENT_UPDATE));
assert_eq!(replacement.merge.as_str().len(), 40);
} else {
panic!("invalid unstaging reason: {:?}", result.old_topic);
}
}
#[test]
fn test_stage_stage_mid_rewrite() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let topic = content_topic(ADD_CONTENT);
let update_topic = content_topic(ADD_CONTENT_REWRITE);
let candidate = CandidateTopic {
old_id: Some(topic.clone()),
new_id: update_topic.clone(),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let result = stager.stage(candidate).unwrap();
assert_eq!(result.results.len(), 2);
let iresult = &result.results[0];
assert!(iresult.on_stage());
let staged_topic = more_content_topic(ADD_MORE_CONTENT);
check_topic_ignore_date(iresult.topic(), &staged_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_MORE_CONTENT));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let iresult = &result.results[1];
assert!(iresult.on_stage());
check_topic_ignore_date(iresult.topic(), &update_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_CONTENT_REWRITE));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let old_topic = result.old_topic.as_ref().unwrap();
assert_eq!(old_topic.topic(), &topic);
if let OldTopicRemoval::Obsoleted {
ref old_merge,
ref replacement,
} = *old_topic
{
assert_eq!(
old_merge,
&StagedTopic {
merge: CommitId::new(ADD_CONTENT_MERGE),
topic,
},
);
let replacement = replacement.as_ref().unwrap();
assert_eq!(replacement.commit(), &CommitId::new(ADD_CONTENT_REWRITE));
assert_eq!(replacement.merge.as_str().len(), 40);
} else {
panic!("invalid unstaging reason: {:?}", result.old_topic);
}
}
#[test]
fn test_stage_stage_mid_conflict() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let topic = content_topic(ADD_CONTENT);
let update_topic = content_topic(ADD_CONTENT_CONFLICT);
let candidate = CandidateTopic {
old_id: Some(topic.clone()),
new_id: update_topic.clone(),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let result = stager.stage(candidate).unwrap();
assert_eq!(result.results.len(), 2);
let iresult = &result.results[0];
assert!(iresult.on_stage());
let staged_topic = more_content_topic(ADD_MORE_CONTENT);
check_topic_ignore_date(iresult.topic(), &staged_topic);
if let IntegrationResult::Staged(ref st) = *iresult {
assert_eq!(st.commit(), &CommitId::new(ADD_MORE_CONTENT));
assert_eq!(st.merge.as_str().len(), 40);
} else {
panic!("invalid integration result: {:?}", iresult);
}
let iresult = &result.results[1];
assert!(!iresult.on_stage());
check_topic_ignore_date(iresult.topic(), &update_topic);
if let IntegrationResult::Unstaged(ref t, ref reason) = *iresult {
assert_eq!(&t.commit, &CommitId::new(ADD_CONTENT_CONFLICT));
format!("{:?}", *reason);
match *reason {
UnstageReason::MergeConflict(ref cs) => {
assert_eq!(cs.len(), 2);
assert_eq!(cs[0].path(), Path::new("more-content"));
assert_eq!(cs[1].path(), Path::new("more-content"));
},
}
} else {
panic!("invalid integration result: {:?}", iresult);
}
let old_topic = result.old_topic.as_ref().unwrap();
assert_eq!(old_topic.topic(), &topic);
if let OldTopicRemoval::Obsoleted {
ref old_merge,
ref replacement,
} = *old_topic
{
assert_eq!(
old_merge,
&StagedTopic {
merge: CommitId::new(ADD_CONTENT_MERGE),
topic,
},
);
assert!(replacement.is_none());
} else {
panic!("invalid unstaging reason: {:?}", result.old_topic);
}
}
#[test]
fn test_stage_stage_unrelated() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(BASE);
let topic = content_topic(STAGE_UNRELATED);
let candidate = CandidateTopic {
old_id: None,
new_id: topic.clone(),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let result = stager.stage(candidate).unwrap();
assert_eq!(result.results.len(), 1);
let iresult = &result.results[0];
assert!(!iresult.on_stage());
check_topic_ignore_date(iresult.topic(), &topic);
if let IntegrationResult::Unmerged(ref t, ref status) = *iresult {
assert_eq!(t, &topic);
if let MergeStatus::NoCommonHistory = status {
} else {
panic!("invalid unmergeable reason: {:?}", status);
}
} else {
panic!("invalid integration result: {:?}", iresult);
}
}
#[test]
fn test_stage_stage_duplicate() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE_DUPLICATE);
let err = Stager::from_branch(&ctx, base, stage).unwrap_err();
if let StagerError::DuplicateTopicId {
id,
} = err
{
assert_eq!(id, 1);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_stage_duplicate_id() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let topic = content_topic(ADD_CONTENT_UPDATE);
let candidate = CandidateTopic {
old_id: None,
new_id: topic.clone(),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let err = stager.stage(candidate).unwrap_err();
if let StagerError::DuplicateTopicId {
id,
} = err
{
assert_eq!(id, topic.id);
} else {
panic!("unexpected error: {:?}", err);
}
}
#[test]
fn test_stage_stage_duplicate_id_consistency() {
let ctx = git_context();
let base = CommitId::new(BASE);
let stage = CommitId::new(STAGE);
let topic = content_topic(ADD_CONTENT_UPDATE);
let old_topic = more_content_topic(ADD_MORE_CONTENT);
let candidate = CandidateTopic {
old_id: Some(old_topic),
new_id: topic.clone(),
};
let mut stager = Stager::from_branch(&ctx, base, stage).unwrap();
let err = stager.stage(candidate).unwrap_err();
if let StagerError::DuplicateTopicId {
id,
} = err
{
assert_eq!(id, topic.id);
} else {
panic!("unexpected error: {:?}", err);
}
}