public void Sync_RepeatedMergeFailure_WeAreLeftOnOurOwnWorkingDefault() { using (var bob = new RepositoryWithFilesSetup("bob", "test.txt", "hello")) using (var sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) using (new FailureSimulator("TextMerger-test.txt")) { bob.WriteNewContentsToTestFile("bobWasHere"); bob.AddAndCheckIn(); sally.WriteNewContentsToTestFile("sallyWasHere"); var result = sally.CheckinAndPullAndMerge(bob); Assert.That(result.Succeeded, Is.False); //make sure we ended up on Sally's revision, even though Bob's are newer var currentRevision = sally.Repository.GetRevisionWorkingSetIsBasedOn(); Assert.AreEqual("sally", sally.Repository.GetRevision(currentRevision.Number.Hash).UserId); //Now do it again bob.WriteNewContentsToTestFile("bobWasHere2"); bob.AddAndCheckIn(); Assert.AreEqual("bob", sally.Repository.GetTip().UserId, "if bob's not the tip, we're not testing the right situation"); result = sally.CheckinAndPullAndMerge(bob); Assert.That(result.Succeeded, Is.False); result = sally.CheckinAndPullAndMerge(bob); Assert.AreEqual("sally", sally.Repository.GetRevisionWorkingSetIsBasedOn().UserId); //sally.ShowInTortoise(); } File.Delete(Path.Combine(Path.GetTempPath(), "TextMerger-test.txt")); }
public void Sync_WeHaveAFileWhichTheyAlsoEditedButHavenotCheckedIn_TheirsIsRenamedToSafetyAndTheyGetOurs() { using (RepositoryWithFilesSetup bob = new RepositoryWithFilesSetup("bob", "test.a9a", "original")) { using (RepositoryWithFilesSetup sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) { File.WriteAllText(bob.ProjectFolder.Combine("problem.txt"), "bob's problem"); //notice, we don't alter the include pattern on bob, so this doesn't get checked in // on his side bob.AddAndCheckIn(); sally.ReplaceSomething("sallyWasHere"); File.WriteAllText(sally.ProjectFolder.Combine("problem.txt"), "sally's problem"); sally.ProjectConfiguration.IncludePatterns.Add("problem.txt"); sally.CheckinAndPullAndMerge(bob); sally.AssertNoErrorsReported(); //ok, so the problem is now lurking in bob's repo, but it doesn't hit him until //he does at least an update bob.CheckinAndPullAndMerge(sally); var rescueFiles = Directory.GetFiles(bob.ProjectFolder.Path, "*.ChorusRescuedFile"); Assert.AreEqual(1, rescueFiles.Length); Assert.AreEqual("bob's problem", File.ReadAllText(rescueFiles[0])); sally.AssertFileContents("problem.txt", "sally's problem"); } } }
public void Sync_BothChangedBinaryFile_FailureReportedOneChosenSingleHead() { using (RepositoryWithFilesSetup bob = new RepositoryWithFilesSetup("bob", "test.a9a", "original")) { using (RepositoryWithFilesSetup sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) { bob.ReplaceSomething("bobWasHere"); bob.AddAndCheckIn(); sally.ReplaceSomething("sallyWasHere"); //now we have a merge of a file type that don't know how to merge sally.CheckinAndPullAndMerge(bob); sally.AssertSingleHead(); bob.AssertSingleHead(); //sally.AssertSingleConflict(c => c.GetType == typeof (UnmergableFileTypeConflict)); sally.AssertSingleConflictType <UnmergableFileTypeConflict>(); // nb: this is sally because the conflict handling mode is (at the time of this test // writing) set to WeWin. Assert.That(File.ReadAllText(sally.UserFile.Path), Does.Contain("sallyWasHere")); } } }
public void Sync_ExceptionInMergeCode_LeftWith2HeadsAndErrorOutputToProgress() { using (RepositoryWithFilesSetup bob = RepositoryWithFilesSetup.CreateWithLiftFile("bob")) { using (RepositoryWithFilesSetup sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) { bob.ReplaceSomething("bobWasHere"); bob.AddAndCheckIn(); sally.ReplaceSomething("sallyWasHere"); using (new FailureSimulator("LiftMerger.FindEntryById")) { sally.CheckinAndPullAndMerge(bob); } Assert.That(sally.ProgressString, Does.Contain("InduceChorusFailure")); sally.AssertHeadCount(2); //ok, Bob's the tip, but... Assert.AreEqual("bob", sally.Repository.GetTip().UserId); //make sure we didn't move up to that tip, because we weren't able to merge with it var currentRevision = sally.GetRepository().GetRevisionWorkingSetIsBasedOn(); Assert.AreEqual("sally", sally.GetRepository().GetRevision(currentRevision.Number.Hash).UserId); Assert.That(File.ReadAllText(sally.UserFile.Path), Does.Contain("sallyWasHere")); //and over at Bob's house, it's as if Sally had never connected bob.AssertHeadCount(1); Assert.AreEqual("bob", bob.Repository.GetTip().UserId); Assert.That(File.ReadAllText(bob.UserFile.Path), Does.Contain("bobWasHere")); } } File.Delete(Path.Combine(Path.GetTempPath(), "LiftMerger.FindEntryById")); }
public void Sync_NewFileWithNonAsciCharacters_FileAdded() { string name = "ŭburux.txt"; using (RepositoryWithFilesSetup bob = new RepositoryWithFilesSetup("bob", name, "original")) { bob.AddAndCheckIn(); bob.AssertNoErrorsReported(); } }
public void Sync_MergeWhenThereIsMoreThanOneHeadToMergeWith_MergesBoth() { using (RepositoryWithFilesSetup bob = new RepositoryWithFilesSetup("bob", "test.a9a", "original")) using (RepositoryWithFilesSetup sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) { var tip = sally.Repository.GetTip(); sally.ReplaceSomething("forbranch1"); sally.AddAndCheckIn(); sally.Repository.Update(tip.Number.Hash); sally.ReplaceSomething("forbranch1"); sally.AddAndCheckIn(); sally.Repository.Update(tip.Number.Hash); sally.ReplaceSomething("forbranch2"); sally.AddAndCheckIn(); sally.Repository.Update(tip.Number.Hash); sally.ReplaceSomething("forbranch3"); sally.AddAndCheckIn(); sally.Repository.Update(tip.Number.Hash); sally.AssertHeadCount(4); bob.ReplaceSomething("bobWasHere"); bob.AddAndCheckIn(); sally.ReplaceSomething("sallyWasHere"); sally.CheckinAndPullAndMerge(bob); sally.AssertNoErrorsReported(); var rescueFiles = Directory.GetFiles(sally.ProjectFolder.Path, "*.ChorusRescuedFile"); Assert.AreEqual(0, rescueFiles.Length); sally.AssertHeadCount(1); } }
public void ConflictFileIsCheckedIn() { using (RepositoryWithFilesSetup bob = RepositoryWithFilesSetup.CreateWithLiftFile("bob")) { using (RepositoryWithFilesSetup sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) { bob.ReplaceSomething("bob"); bob.AddAndCheckIn(); sally.ReplaceSomething("sally"); sally.CheckinAndPullAndMerge(bob); string notesFile = ChorusNotesMergeEventListener.GetChorusNotesFilePath(sally.UserFile.Path); Console.WriteLine("notesFile '{0}'", notesFile); Assert.That(notesFile, Does.Exist, "Conflict file should have been in working set"); Assert.That(sally.Synchronizer.Repository.GetFileIsInRepositoryFromFullPath(notesFile), Is.True, "Notes file should have been added to repository"); } } }
public void Sync_MergeFailure_LeavesNoChorusMergeProcessAlive() { using (RepositoryWithFilesSetup bob = RepositoryWithFilesSetup.CreateWithLiftFile("bob")) { using (RepositoryWithFilesSetup sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) { bob.ReplaceSomething("bobWasHere"); bob.AddAndCheckIn(); sally.ReplaceSomething("sallyWasHere"); using (new FailureSimulator("LiftMerger.FindEntryById")) { sally.CheckinAndPullAndMerge(bob); } Assert.AreEqual(0, Process.GetProcessesByName("ChorusMerge").Length); } } File.Delete(Path.Combine(Path.GetTempPath(), "LiftMerger.FindEntryById")); }
public void Sync_WeHaveUntrackedFile_NotRenamed() { using (RepositoryWithFilesSetup bob = new RepositoryWithFilesSetup("bob", "test.a9a", "original")) { using (RepositoryWithFilesSetup sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) { File.WriteAllText(bob.ProjectFolder.Combine("somethingNew.txt"), "blah"); bob.ProjectConfiguration.IncludePatterns.Add("somethingNew.txt"); bob.AddAndCheckIn(); sally.ReplaceSomething("sallyWasHere"); File.WriteAllText(sally.ProjectFolder.Combine("untracked.txt"), "foo"); sally.CheckinAndPullAndMerge(bob); sally.AssertNoErrorsReported(); var rescueFiles = Directory.GetFiles(sally.ProjectFolder.Path, "*.ChorusRescuedFile"); Assert.AreEqual(0, rescueFiles.Length); } } }
public void Sync_BothChangedBinaryFile_FailureReportedOneChosenSingleHead() { using (RepositoryWithFilesSetup bob = new RepositoryWithFilesSetup("bob", "test.a9a", "original")) { using (RepositoryWithFilesSetup sally = RepositoryWithFilesSetup.CreateByCloning("sally", bob)) { bob.ReplaceSomething("bobWasHere"); bob.AddAndCheckIn(); sally.ReplaceSomething("sallyWasHere"); //now we have a merge of a file type that don't know how to merge sally.CheckinAndPullAndMerge(bob); sally.AssertSingleHead(); bob.AssertSingleHead(); //sally.AssertSingleConflict(c => c.GetType == typeof (UnmergableFileTypeConflict)); sally.AssertSingleConflictType<UnmergableFileTypeConflict>(); // nb: this is sally because the conflict handling mode is (at the time of this test // writing) set to WeWin. Assert.IsTrue(File.ReadAllText(sally.UserFile.Path).Contains("sallyWasHere")); } } }
[Category("UnknownMonoIssue")] // It insists on failing on mono, for some reason. public void EnsureRightPersonMadeChanges() { const string commonAncestor = @"<?xml version='1.0' encoding='utf-8'?> <Lexicon> <header> <LexDb guid='2d23f428-83a9-44ba-90f1-9e3264b5b982' > <DateCreated val='2012-12-10 6:29:17.117' /> <DateModified val='2012-12-10 6:29:17.117' /> <IsHeadwordCitationForm val='True' /> <IsBodyInSeparateSubentry val='True' /> </LexDb> </header> <LexEntry guid='ffdc58c9-5cc3-469f-9118-9f18c0138d02'> <DateCreated val='2012-12-10 6:29:17.117' /> <DateModified val='2012-12-10 6:29:17.117' /> <HomographNumber val='1' /> <DoNotUseForParsing val='True' /> <ExcludeAsHeadword val='True' /> <Senses> <ownseq class='LexSense' guid='97129e67-e0a5-47c4-a875-05c2b2e1b7df'> <Custom name='Paradigm'> <AStr ws='qaa-x-ezpi'> <Run ws='qaa-x-ezpi'>saklo, yzaklo, rzaklo, wzaklo, nzaklo, -</Run> </AStr> </Custom> </ownseq> </Senses> </LexEntry> </Lexicon>"; const string sue = @"<?xml version='1.0' encoding='utf-8'?> <Lexicon> <header> <LexDb guid='2d23f428-83a9-44ba-90f1-9e3264b5b982' > <DateCreated val='2012-12-10 6:29:17.117' /> <DateModified val='2012-12-10 6:29:17.117' /> <IsHeadwordCitationForm val='True' /> <IsBodyInSeparateSubentry val='True' /> </LexDb> </header> <LexEntry guid='ffdc58c9-5cc3-469f-9118-9f18c0138d02'> <DateCreated val='2012-12-10 6:29:17.117' /> <DateModified val='2012-12-10 6:29:17.117' /> <HomographNumber val='1' /> <DoNotUseForParsing val='True' /> <ExcludeAsHeadword val='True' /> <Senses> <ownseq class='LexSense' guid='97129e67-e0a5-47c4-a875-05c2b2e1b7df'> <Custom name='Paradigm'> <AStr ws='qaa-x-ezpi'> <Run ws='qaa-x-ezpi'>saglo, yzaglo, rzaglo, wzaglo, nzaglo, -</Run> </AStr> </Custom> </ownseq> </Senses> </LexEntry> </Lexicon>"; const string randy = @"<?xml version='1.0' encoding='utf-8'?> <Lexicon> <header> <LexDb guid='2d23f428-83a9-44ba-90f1-9e3264b5b982' > </LexDb> </header> <LexEntry guid='ffdc58c9-5cc3-469f-9118-9f18c0138d02'> <Senses> <ownseq class='LexSense' guid='97129e67-e0a5-47c4-a875-05c2b2e1b7df'> <Custom name='Paradigm'> <AStr ws='zpi'> <Run ws='zpi'>saklo, yzaklo, rzaklo, wzaklo, nzaklo, -</Run> </AStr> </Custom> </ownseq> </Senses> </LexEntry> </Lexicon>"; var mdc = MetadataCache.TestOnlyNewCache; using (var sueRepo = new RepositoryWithFilesSetup("Sue", string.Format("{0}_01.{1}", SharedConstants.Lexicon, SharedConstants.Lexdb), commonAncestor)) { var sueProjPath = sueRepo.ProjectFolder.Path; // Add model version number file. var modelVersionPathname = Path.Combine(sueProjPath, SharedConstants.ModelVersionFilename); File.WriteAllText(modelVersionPathname, AnnotationImages.kModelVersion); sueRepo.Repository.TestOnlyAddSansCommit(modelVersionPathname); // Add custom property data file. var customPropsPathname = Path.Combine(sueProjPath, SharedConstants.CustomPropertiesFilename); File.WriteAllText(customPropsPathname, CustomPropData); sueRepo.Repository.TestOnlyAddSansCommit(customPropsPathname); sueRepo.AddAndCheckIn(); using (var randyRepo = RepositoryWithFilesSetup.CreateByCloning("Randy", sueRepo)) { // By doing the clone first, we get the common starting state in both repos. sueRepo.WriteNewContentsToTestFile(sue); sueRepo.AddAndCheckIn(); var mergeConflictsNotesFile = ChorusNotesMergeEventListener.GetChorusNotesFilePath(randyRepo.UserFile.Path); Assert.IsFalse(File.Exists(mergeConflictsNotesFile), "ChorusNotes file should NOT have been in working set."); randyRepo.WriteNewContentsToTestFile(randy); randyRepo.CheckinAndPullAndMerge(sueRepo); Assert.IsTrue(File.Exists(mergeConflictsNotesFile), "ChorusNotes file should have been in working set."); var notesContents = File.ReadAllText(mergeConflictsNotesFile); Assert.IsNotNullOrEmpty(notesContents); Assert.That(notesContents, Is.StringContaining("Removed Vs Edited Element Conflict")); Assert.That(notesContents, Is.StringContaining("Randy deleted this element")); Assert.That(notesContents, Is.StringContaining("Sue edited it")); Assert.That(notesContents, Is.StringContaining("The merger kept the change made by Sue.")); Assert.That(notesContents, Is.StringContaining("whoWon=\"Sue\"")); Assert.That(notesContents, Is.StringContaining("alphaUserId=\"Randy\"")); Assert.That(notesContents, Is.StringContaining("betaUserId=\"Sue\"")); // Make sure merged file has both alts. var doc = XDocument.Load(randyRepo.UserFile.Path); var customParadigmElement = doc.Root.Element("LexEntry").Element("Senses").Element("ownseq").Element("Custom"); var aStrElements = customParadigmElement.Elements("AStr").ToList(); Assert.AreEqual(2, aStrElements.Count); var aStrZpi = aStrElements.FirstOrDefault(el => el.Attribute("ws").Value == "zpi"); Assert.IsNotNull(aStrZpi); Assert.IsTrue(aStrZpi.Element("Run").Value == "saklo, yzaklo, rzaklo, wzaklo, nzaklo, -"); var aStrEzpi = aStrElements.FirstOrDefault(el => el.Attribute("ws").Value == "qaa-x-ezpi"); Assert.IsNotNull(aStrEzpi); Assert.IsTrue(aStrEzpi.Element("Run").Value == "saglo, yzaglo, rzaglo, wzaglo, nzaglo, -"); } } }
[Category("UnknownMonoIssue")] // Do3WayMerge is never called on Mono, for some reason. public void EnsureDictionaryConfigsUseDictionaryStrategy() { const string commonAncestor = @"<?xml version='1.0' encoding='utf-8'?> <DictionaryConfiguration name='Root-based (complex forms as subentries)' allPublications='true' version='1' lastModified='2014-10-07'> <ConfigurationItem name='Main Entry' style='Dictionary-Normal' isEnabled='true' field='LexEntry' cssClassNameOverride='entry'> <ParagraphOptions paragraphStyle='Dictionary-Normal' continuationParagraphStyle='Dictionary-Continuation' /> <ConfigurationItem name='Headword' between=' ' after=' ' style='Dictionary-Headword' isEnabled='true' field='MLHeadWord' cssClassNameOverride='mainheadword'> <WritingSystemOptions writingSystemType='vernacular' displayWSAbreviation='false'> <Option id='vernacular' isEnabled='true'/> </WritingSystemOptions> </ConfigurationItem> <ConfigurationItem name='Variant Forms' before='(' between='; ' after=') ' isEnabled='true' field='VariantFormEntryBackRefs'> <ListTypeOptions list='variant'> <Option isEnabled='true' id='b0000000-c40e-433e-80b5-31da08771344'/> <Option isEnabled='false' id='0c4663b3-4d9a-47af-b9a1-c8565d8112ed'/> </ListTypeOptions> </ConfigurationItem> </ConfigurationItem> </DictionaryConfiguration>"; const string sue = @"<?xml version='1.0' encoding='utf-8'?> <DictionaryConfiguration name='Root-based (complex forms as subentries)' allPublications='true' version='1' lastModified='2014-10-07'> <ConfigurationItem name='Main Entry' style='Dictionary-Normal' isEnabled='true' field='LexEntry' cssClassNameOverride='entry'> <ParagraphOptions paragraphStyle='Dictionary-Normal' continuationParagraphStyle='Dictionary-Continuation' /> <ConfigurationItem name='Headword' between=' ' after=' ' style='Dictionary-Headword' isEnabled='true' field='MLHeadWord' cssClassNameOverride='mainheadword'> <WritingSystemOptions writingSystemType='vernacular' displayWSAbreviation='false'> <Option id='vernacular' isEnabled='false'/> <Option id='fr' isEnabled='true' /> </WritingSystemOptions> </ConfigurationItem> <ConfigurationItem name='Variant Forms' before='(' between='; ' after=') ' isEnabled='true' field='VariantFormEntryBackRefs'> <ListTypeOptions list='variant'> <Option isEnabled='true' id='b0000000-c40e-433e-80b5-31da08771344'/> <Option isEnabled='false' id='0c4663b3-4d9a-47af-b9a1-c8565d8112ed'/> </ListTypeOptions> </ConfigurationItem> </ConfigurationItem> </DictionaryConfiguration>"; const string randy = @"<?xml version='1.0' encoding='utf-8'?> <DictionaryConfiguration name='Root-based (complex forms as subentries)' allPublications='true' version='1' lastModified='2014-10-07'> <ConfigurationItem name='Main Entry' style='Dictionary-Normal' isEnabled='true' field='LexEntry' cssClassNameOverride='entry'> <ParagraphOptions paragraphStyle='Dictionary-Normal' continuationParagraphStyle='Dictionary-Continuation' /> <ConfigurationItem name='Headword' between=' ' after=' ' style='Dictionary-Headword' isEnabled='true' field='MLHeadWord' cssClassNameOverride='mainheadword'> <WritingSystemOptions writingSystemType='vernacular' displayWSAbreviation='false'> <Option id='vernacular' isEnabled='true'/> </WritingSystemOptions> </ConfigurationItem> <ConfigurationItem name='Variant Forms' before='(' between='; ' after=') ' isEnabled='true' field='VariantFormEntryBackRefs'> <ListTypeOptions list='variant'> <Option isEnabled='false' id='b0000000-c40e-433e-80b5-31da08771344'/> <Option isEnabled='true' id='0c4663b3-4d9a-47af-b9a1-c8565d8112ed'/> </ListTypeOptions> </ConfigurationItem> </ConfigurationItem> </DictionaryConfiguration>"; using (var tempFolder = new TemporaryFolder("Temp")) { // Copy the Dictionary Configuration Schema to where the Dictionary Configuration Handler Strategy looks var appsDir = Path.GetDirectoryName(Utilities.StripFilePrefix(Assembly.GetExecutingAssembly().CodeBase)); var xsdPath = Path.Combine(appsDir, "TestData", "Language Explorer", "Configuration", SharedConstants.DictConfigSchemaFilename); var xsdPathInProj = Path.Combine(tempFolder.Path, SharedConstants.DictConfigSchemaFilename); File.Copy(xsdPath, xsdPathInProj, true); using (var sueRepo = new RepositoryWithFilesSetup("Sue", string.Format("root.{0}", SharedConstants.fwdictconfig), commonAncestor)) using (var randyRepo = RepositoryWithFilesSetup.CreateByCloning("Randy", sueRepo)) { // By doing the clone before making Sue's changes, we get the common starting state in both repos. sueRepo.WriteNewContentsToTestFile(sue); sueRepo.AddAndCheckIn(); var mergeConflictsNotesFile = ChorusNotesMergeEventListener.GetChorusNotesFilePath(randyRepo.UserFile.Path); Assert.IsFalse(File.Exists(mergeConflictsNotesFile), "ChorusNotes file should NOT have been in working set."); randyRepo.WriteNewContentsToTestFile(randy); randyRepo.CheckinAndPullAndMerge(sueRepo); Assert.IsTrue(File.Exists(mergeConflictsNotesFile), "ChorusNotes file should have been in working set."); var notesContents = File.ReadAllText(mergeConflictsNotesFile); Assert.IsNotNullOrEmpty(notesContents); Assert.That(notesContents, Is.StringContaining("Randy and Sue edited the same part of this data.")); Assert.That(notesContents, Is.StringContaining("The merger kept the change made by Randy.")); Assert.That(notesContents, Is.StringContaining("alphaUserId=\"Randy\"")); Assert.That(notesContents, Is.StringContaining("betaUserId=\"Sue\"")); // Make sure merged file has Randy's changes var doc = XDocument.Load(randyRepo.UserFile.Path); var options = doc.Root.Element("ConfigurationItem").Elements("ConfigurationItem").Last(/*Variant Forms*/) .Element("ListTypeOptions").Elements("Option").ToList(); Assert.AreEqual(2, options.Count, "There should be two Variant Forms options"); Assert.AreEqual("b0000000-c40e-433e-80b5-31da08771344", options[0].Attribute("id").Value, "Options are out of order"); Assert.AreEqual("0c4663b3-4d9a-47af-b9a1-c8565d8112ed", options[1].Attribute("id").Value, "Options are out of order"); Assert.AreEqual("false", options[0].Attribute("isEnabled").Value, "First option should be disabled"); Assert.AreEqual("true", options[1].Attribute("isEnabled").Value, "Second option should be enabled"); // Make sure merged file does *not* have Sue's changes options = doc.Root.Element("ConfigurationItem").Element("ConfigurationItem" /*Headword*/) .Element("WritingSystemOptions").Elements("Option").ToList(); Assert.AreEqual(1, options.Count, "There should be only one WS Option"); Assert.AreEqual("vernacular", options[0].Attribute("id").Value, "should be default vernacular"); Assert.AreEqual("true", options[0].Attribute("isEnabled").Value, "should be enabled"); } } }
[Category("UnknownMonoIssue")] // It insists on failing on mono, for some reason. public void EnsureRightPersonMadeChanges() { const string commonAncestor = @"<?xml version='1.0' encoding='utf-8'?> <Lexicon> <header> <LexDb guid='2d23f428-83a9-44ba-90f1-9e3264b5b982' > <DateCreated val='2012-12-10 6:29:17.117' /> <DateModified val='2012-12-10 6:29:17.117' /> <IsHeadwordCitationForm val='True' /> <IsBodyInSeparateSubentry val='True' /> </LexDb> </header> <LexEntry guid='ffdc58c9-5cc3-469f-9118-9f18c0138d02'> <DateCreated val='2012-12-10 6:29:17.117' /> <DateModified val='2012-12-10 6:29:17.117' /> <HomographNumber val='1' /> <DoNotUseForParsing val='True' /> <ExcludeAsHeadword val='True' /> <Senses> <ownseq class='LexSense' guid='97129e67-e0a5-47c4-a875-05c2b2e1b7df'> <Custom name='Paradigm'> <AStr ws='qaa-x-ezpi'> <Run ws='qaa-x-ezpi'>saklo, yzaklo, rzaklo, wzaklo, nzaklo, -</Run> </AStr> </Custom> </ownseq> </Senses> </LexEntry> </Lexicon>"; const string sue = @"<?xml version='1.0' encoding='utf-8'?> <Lexicon> <header> <LexDb guid='2d23f428-83a9-44ba-90f1-9e3264b5b982' > <DateCreated val='2012-12-10 6:29:17.117' /> <DateModified val='2012-12-10 6:29:17.117' /> <IsHeadwordCitationForm val='True' /> <IsBodyInSeparateSubentry val='True' /> </LexDb> </header> <LexEntry guid='ffdc58c9-5cc3-469f-9118-9f18c0138d02'> <DateCreated val='2012-12-10 6:29:17.117' /> <DateModified val='2012-12-10 6:29:17.117' /> <HomographNumber val='1' /> <DoNotUseForParsing val='True' /> <ExcludeAsHeadword val='True' /> <Senses> <ownseq class='LexSense' guid='97129e67-e0a5-47c4-a875-05c2b2e1b7df'> <Custom name='Paradigm'> <AStr ws='qaa-x-ezpi'> <Run ws='qaa-x-ezpi'>saglo, yzaglo, rzaglo, wzaglo, nzaglo, -</Run> </AStr> </Custom> </ownseq> </Senses> </LexEntry> </Lexicon>"; const string randy = @"<?xml version='1.0' encoding='utf-8'?> <Lexicon> <header> <LexDb guid='2d23f428-83a9-44ba-90f1-9e3264b5b982' > </LexDb> </header> <LexEntry guid='ffdc58c9-5cc3-469f-9118-9f18c0138d02'> <Senses> <ownseq class='LexSense' guid='97129e67-e0a5-47c4-a875-05c2b2e1b7df'> <Custom name='Paradigm'> <AStr ws='zpi'> <Run ws='zpi'>saklo, yzaklo, rzaklo, wzaklo, nzaklo, -</Run> </AStr> </Custom> </ownseq> </Senses> </LexEntry> </Lexicon>"; const string customPropData = @"<?xml version='1.0' encoding='utf-8'?> <AdditionalFields> <CustomField class='LexEntry' destclass='7' key='LexEntryTone' listRoot='53241fd4-72ae-4082-af55-6b659657083c' name='Tone' type='ReferenceCollection' /> <CustomField class='LexSense' key='LexSenseParadigm' name='Paradigm' type='MultiString' wsSelector='-2' /> <CustomField class='WfiWordform' key='WfiWordformCertified' name='Certified' type='Boolean' /> </AdditionalFields>"; var mdc = MetadataCache.TestOnlyNewCache; using (var sueRepo = new RepositoryWithFilesSetup("Sue", string.Format("{0}_01.{1}", SharedConstants.Lexicon, SharedConstants.Lexdb), commonAncestor)) { var sueProjPath = sueRepo.ProjectFolder.Path; // Add model version number file. var modelVersionPathname = Path.Combine(sueProjPath, SharedConstants.ModelVersionFilename); File.WriteAllText(modelVersionPathname, AnnotationImages.kModelVersion); sueRepo.Repository.TestOnlyAddSansCommit(modelVersionPathname); // Add custom property data file. var customPropsPathname = Path.Combine(sueProjPath, SharedConstants.CustomPropertiesFilename); File.WriteAllText(customPropsPathname, customPropData); sueRepo.Repository.TestOnlyAddSansCommit(customPropsPathname); sueRepo.AddAndCheckIn(); using (var randyRepo = RepositoryWithFilesSetup.CreateByCloning("Randy", sueRepo)) { // By doing the clone first, we get the common starting state in both repos. sueRepo.WriteNewContentsToTestFile(sue); sueRepo.AddAndCheckIn(); var mergeConflictsNotesFile = ChorusNotesMergeEventListener.GetChorusNotesFilePath(randyRepo.UserFile.Path); Assert.IsFalse(File.Exists(mergeConflictsNotesFile), "ChorusNotes file should NOT have been in working set."); randyRepo.WriteNewContentsToTestFile(randy); randyRepo.CheckinAndPullAndMerge(sueRepo); Assert.IsTrue(File.Exists(mergeConflictsNotesFile), "ChorusNotes file should have been in working set."); var notesContents = File.ReadAllText(mergeConflictsNotesFile); Assert.IsNotNullOrEmpty(notesContents); Assert.IsTrue(notesContents.Contains("Removed Vs Edited Element Conflict")); Assert.IsTrue(notesContents.Contains("Randy deleted this element")); Assert.IsTrue(notesContents.Contains("Sue edited it")); Assert.IsTrue(notesContents.Contains("The merger kept the change made by Sue.")); Assert.IsTrue(notesContents.Contains("whoWon=\"Sue\"")); Assert.IsTrue(notesContents.Contains("alphaUserId=\"Randy\"")); Assert.IsTrue(notesContents.Contains("betaUserId=\"Sue\"")); // Make sure merged file has both alts. var doc = XDocument.Load(randyRepo.UserFile.Path); var customParadigmElement = doc.Root.Element("LexEntry").Element("Senses").Element("ownseq").Element("Custom"); var aStrElements = customParadigmElement.Elements("AStr").ToList(); Assert.AreEqual(2, aStrElements.Count); var aStrZpi = aStrElements.FirstOrDefault(el => el.Attribute("ws").Value == "zpi"); Assert.IsNotNull(aStrZpi); Assert.IsTrue(aStrZpi.Element("Run").Value == "saklo, yzaklo, rzaklo, wzaklo, nzaklo, -"); var aStrEzpi = aStrElements.FirstOrDefault(el => el.Attribute("ws").Value == "qaa-x-ezpi"); Assert.IsNotNull(aStrEzpi); Assert.IsTrue(aStrEzpi.Element("Run").Value == "saglo, yzaglo, rzaglo, wzaglo, nzaglo, -"); } } }
public void Sync_RepeatedMergeFailure_WeAreLeftOnOurOwnWorkingDefault() { using (var bob = new RepositoryWithFilesSetup("bob", "test.txt", "hello")) using (var sally = RepositoryWithFilesSetup.CreateByCloning("sally",bob)) using (new FailureSimulator("TextMerger-test.txt")) { bob.WriteNewContentsToTestFile("bobWasHere"); bob.AddAndCheckIn(); sally.WriteNewContentsToTestFile("sallyWasHere"); var result = sally.CheckinAndPullAndMerge(bob); Assert.IsFalse(result.Succeeded); //make sure we ended up on Sally's revision, even though Bob's are newer var currentRevision = sally.Repository.GetRevisionWorkingSetIsBasedOn(); Assert.AreEqual("sally", sally.Repository.GetRevision(currentRevision.Number.Hash).UserId); //Now do it again bob.WriteNewContentsToTestFile("bobWasHere2"); bob.AddAndCheckIn(); Assert.AreEqual("bob", sally.Repository.GetTip().UserId,"if bob's not the tip, we're not testing the right situation"); result = sally.CheckinAndPullAndMerge(bob); Assert.IsFalse(result.Succeeded); result = sally.CheckinAndPullAndMerge(bob); Assert.AreEqual("sally",sally.Repository.GetRevisionWorkingSetIsBasedOn().UserId); //sally.ShowInTortoise(); } File.Delete(Path.Combine(Path.GetTempPath(), "TextMerger-test.txt")); }