Example #1
0
        protected override void DoTest()
        {
            // Create the modification and library spec used in this test
            var phosphoLossMod = new StaticMod("Phospho Loss", "S, T", null, true, "HPO3",
                                               LabelAtoms.None, RelativeRT.Matching, null, null, new[] { new FragmentLoss("H3PO4"), });
            var multipleLossMod = new StaticMod("Multiple Loss-only", "D", null, false, null,
                                                LabelAtoms.None, RelativeRT.Matching, null, null, new[]
            {
                new FragmentLoss("NH3"),
                new FragmentLoss("H2O"),
                new FragmentLoss(null, 20, 25)
            });
            var heavyKMod   = new StaticMod("Heavy K", "K", ModTerminus.C, null, LabelAtoms.C13 | LabelAtoms.N15, null, null);
            var librarySpec = new BiblioSpecLiteSpec("Phospho Library",
                                                     TestFilesDir.GetTestPath("phospho_30882_v2.blib"));

            // Prepare settings for this test
            Settings.Default.StaticModList.Clear();
            Settings.Default.StaticModList.AddRange(StaticModList.GetDefaultsOn());
            Settings.Default.StaticModList.Add(phosphoLossMod);
            Settings.Default.HeavyModList.Clear();
            Settings.Default.HeavyModList.Add(heavyKMod);
            Settings.Default.SpectralLibraryList.Clear();
            Settings.Default.SpectralLibraryList.Add(librarySpec);

            // Prepare document settings for this test
            const int countIons = 6;
            var       settings  = SrmSettingsList.GetDefault()
                                  .ChangePeptideModifications(mods => mods.ChangeStaticModifications(new List <StaticMod>(mods.StaticModifications)
            {
                phosphoLossMod
            }))
                                  .ChangePeptideLibraries(lib => lib.ChangeLibrarySpecs(new[] { librarySpec }))
                                  .ChangeTransitionLibraries(tlib => tlib.ChangeIonCount(countIons));

            RunUI(() => SkylineWindow.ModifyDocument("Set test settings",
                                                     doc => doc.ChangeSettings(settings)));

            WaitForDocumentLoaded();

            // Add FASTA sequence
            RunUI(() => SkylineWindow.Paste(TEXT_FASTA_SPROT));

            var docLibLoss = SkylineWindow.Document;

            AssertEx.IsDocumentState(docLibLoss, null, 3, 4, 24);
            Assert.AreEqual(7, GetLossCount(docLibLoss, 1));

            string lossLabel = "-" + Math.Round(phosphoLossMod.Losses[0].MonoisotopicMass, 1);

            for (int i = 0; i < docLibLoss.PeptideTransitionGroupCount; i++)
            {
                var pathTranGroup = docLibLoss.GetPathTo((int)SrmDocument.Level.TransitionGroups, i);
                var nodeGroup     = (TransitionGroupDocNode)docLibLoss.FindNode(pathTranGroup);
                if (!nodeGroup.Children.Contains(child => ((TransitionDocNode)child).HasLoss))
                {
                    continue;
                }

                // Select the transition groups that contain loss ions
                SelectNode(SrmDocument.Level.TransitionGroups, i);
                WaitForGraphs();

                // Make sure the spectrum graph contains some -98 ions
                RunUI(() => Assert.IsTrue(SkylineWindow.GraphSpectrum.IonLabels.Contains(label => label.Contains(lossLabel)),
                                          string.Format("Missing loss labels in spectrum graph for {0}", nodeGroup.TransitionGroup.Peptide.Target)));

                // Make sure the transition tree nodes contain -98 ions
                RunUI(() => Assert.IsTrue(GetChildLabels(SkylineWindow.SelectedNode).Contains(label => label.Contains(lossLabel)),
                                          string.Format("Missing loss labels in transition tree nodes for {0}", nodeGroup.TransitionGroup.Peptide.Target)));
            }

            // Make the settings significantly more complex
            // - 2 neutral losses
            // - a second modification with 3 potential neutral losses
            // - a heavy labeling modification
            // - only ions between precursor m/z and last ion
            // - allow both y- and b- ions
            // - no proline peaks
            // - only use filtered ions to match library
            RunUI(() => SkylineWindow.ModifyDocument("Set test settings", doc =>
                                                     doc.ChangeSettings(doc.Settings.ChangePeptideModifications(mod =>
                                                                                                                mod.ChangeMaxNeutralLosses(2)
                                                                                                                .ChangeStaticModifications(new List <StaticMod>(mod.StaticModifications)
            {
                multipleLossMod
            })
                                                                                                                .ChangeModifications(IsotopeLabelType.heavy, new[] { heavyKMod }))
                                                                        .ChangeTransitionFilter(filter =>
                                                                                                filter.ChangeFragmentRangeFirstName("m/z > precursor")
                                                                                                .ChangeFragmentRangeLastName("last ion")
                                                                                                .ChangePeptideIonTypes(new[] { IonType.y, IonType.b })
                                                                                                .ChangeMeasuredIons(new MeasuredIon[0]))
                                                                        .ChangeTransitionLibraries(lib =>
                                                                                                   lib.ChangePick(TransitionLibraryPick.filter)))));

            var docComplex = WaitForDocumentChange(docLibLoss);

            // The document has 2 variable mod peptides at the protein terminus
            Assert.AreEqual(docLibLoss.PeptideTransitionGroupCount * 2 - 2, docComplex.PeptideTransitionGroupCount);
            Assert.AreEqual(4, GetLossCount(docComplex, 2));
            Assert.AreEqual(16, GetLossCount(docComplex, 1));
            foreach (var nodePep in docComplex.Peptides)
            {
                if (nodePep.Children.Count != 2)
                {
                    continue;
                }
                var nodeGroup1 = (TransitionGroupDocNode)nodePep.Children[0];
                var nodeGroup2 = (TransitionGroupDocNode)nodePep.Children[1];

                Assert.IsTrue(nodeGroup1.EquivalentChildren(nodeGroup2));
            }
            // CONSIDER: Can't check cloned because of libraries.  Maybe add a new method for this
            // AssertEx.Serializable(docComplex, AssertEx.DocumentCloned);

            SelectNode(SrmDocument.Level.Molecules, 1);
            WaitForGraphs();

            // Verify that the ion labels in the graph match those in the tree view
            RunUI(() =>
            {
                var nodePepSelected = (PeptideDocNode)docComplex.FindNode(SkylineWindow.SelectedPath);
                string[] ionLabels  = SkylineWindow.GraphSpectrum.IonLabels.ToArray();

                foreach (TransitionGroupDocNode nodeGroup in nodePepSelected.Children)
                {
                    var setSeenRanks = new HashSet <int>();
                    foreach (TransitionDocNode nodeTran in nodeGroup.Children)
                    {
                        Assert.IsTrue(nodeTran.HasLibInfo);
                        // Make sure the rank has not been seen
                        int rankTran = nodeTran.LibInfo.Rank;
                        Assert.IsFalse(setSeenRanks.Contains(rankTran));
                        setSeenRanks.Add(rankTran);
                        // And it is within the expected range
                        Assert.IsTrue(1 <= rankTran && rankTran <= countIons);
                        // Make sure there is a matching label in the spectrum graph
                        var regexRank = nodeTran.HasLoss ?
                                        new Regex(string.Format(@"(\w)(\d+) -([^ +]+).* \({0}\)", string.Format(Resources.AbstractSpectrumGraphItem_GetLabel_rank__0__, rankTran))) :
                                        new Regex(string.Format(@"(\w)(\d+).* \({0}\)", string.Format(Resources.AbstractSpectrumGraphItem_GetLabel_rank__0__, rankTran)));
                        int iLabel = ionLabels.IndexOf(regexRank.IsMatch);
                        Assert.IsTrue(iLabel != -1);
                        var match = regexRank.Match(ionLabels[iLabel]);
                        Assert.AreEqual(nodeTran.Transition.IonType.ToString(), match.Groups[1].Value);
                        Assert.AreEqual(nodeTran.Transition.Ordinal, int.Parse(match.Groups[2].Value));
                        if (nodeTran.HasLoss)
                        {
                            Assert.AreEqual(nodeTran.Losses.Mass, double.Parse(match.Groups[3].Value), 0.1);
                        }
                    }
                }
            });

            // Make sure setting losses as included Never works
            {
                var docBeforeNever         = SkylineWindow.Document;
                var peptideSettingsUINever = ShowDialog <PeptideSettingsUI>(() =>
                                                                            SkylineWindow.ShowPeptideSettingsUI(PeptideSettingsUI.TABS.Modifications));
                var editModsDlgNever = ShowEditStaticModsDlg(peptideSettingsUINever);
                RunUI(() => editModsDlgNever.SelectItem(phosphoLossMod.Name));
                var editModDlgNever = ShowDialog <EditStaticModDlg>(editModsDlgNever.EditItem);
                RunUI(() => editModDlgNever.LossSelectedIndex = 0);
                RunDlg <EditFragmentLossDlg>(editModDlgNever.EditLoss, dlg =>
                {
                    dlg.Inclusion = LossInclusion.Never;
                    dlg.OkDialog();
                });
                RunDlg <MultiButtonMsgDlg>(editModDlgNever.OkDialog, dlg => dlg.Btn1Click());
                OkDialog(editModsDlgNever, editModsDlgNever.OkDialog);
                OkDialog(peptideSettingsUINever, peptideSettingsUINever.OkDialog);
                var docAfterNever = WaitForDocumentChange(docBeforeNever);
                Assert.AreEqual(0, GetLossCount(docAfterNever, 1));
            }
        }
Example #2
0
        public void TestModificationMatcher()
        {
            InitSeqs();

            var carbC = StaticModList.GetDefaultsOn()[0];

            // Test exception thrown if unable to match - mass.
            UpdateMatcherFail(STR_FAIL_MASS);
            UpdateMatcherFail(STR_FAIL_NOT_A_NUMBER);
            // Test exception thrown if unable to match - name.
            UpdateMatcherFail(STR_FAIL_NAME);
            // Can't match empty modifications.
            UpdateMatcherFail(STR_FAIL_EMPTY_MOD);
            UpdateMatcherFail(STR_FAIL_EMPTY_MOD2);
            // Can't match double modifications.
            UpdateMatcherFail(STR_FAIL_DOUBLE_MOD);
            // Test exception thrown if unimod not specified correctly
            UpdateMatcherFail(STR_FAIL_UNIMOD);
            UpdateMatcherFail(STR_UNKNOWN_UNIMOD);
            // Can't phosphorylate tryptophan
            UpdateMatcherFail(STR_FAIL_WRONG_AA_UNIMOD);
            // Can't put C-terminal modification in middle of peptide
            UpdateMatcherFail(STR_FAIL_UNIMOD_TERMINUS);

            // Test mods in UniMod match correctly.
            UpdateMatcher(StaticModList.GetDefaultsOn(), HeavyModList.GetDefaultsOn(), null, null);
            // A sequence with no modifications should not be explicitly modified.
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_NO_MODS).HasExplicitMods);
            var nodeCysOxi = MATCHER.GetModifiedNode(STR_CYS_AND_OXI);

            Assert.IsTrue(nodeCysOxi.HasExplicitMods);
            Assert.IsFalse(nodeCysOxi.ExplicitMods.HasHeavyModifications);
            // Modifications should match by name.
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_MOD_BY_NAME).ExplicitMods.StaticModifications.Contains(mod =>
                                                                                                             Equals(mod.Modification.Name, "Phospho (ST)")));
            // Test can find terminal modification
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_TERM_ONLY).ExplicitMods.HeavyModifications.Contains(mod =>
                                                                                                          mod.Modification.EquivalentAll(UniMod.GetModification("Label:13C(6) (C-term R)", false))));
            // Test can find matches on terminus that are not terminal
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_MOD_BY_NAME).ExplicitMods.StaticModifications.Contains(mod =>
                                                                                                             mod.Modification.Terminus == null));
            // Test matching negative masses
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_AMMONIA_LOSS).ExplicitMods.StaticModifications.Contains(mod =>
                                                                                                              mod.Modification.EquivalentAll(UniMod.GetModification("Ammonia-loss (N-term C)", true))));

            // General and specific
            // If all AAs modified, try for most general modification.
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_HEAVY_15)
                          .ExplicitMods.HeavyModifications.Contains(mod => mod.Modification.Equivalent(LABEL15_N)));

            // Updating the settings.
            // Peptide settings should change to include new mods.
            var          docNew = new SrmDocument(SrmSettingsList.GetDefault());
            IdentityPath firstAdded;
            IdentityPath nextAdded;

            docNew = docNew.AddPeptideGroups(new[] { new PeptideGroupDocNode(new PeptideGroup(), "PepGroup1", "",
                                                                             new[] { MATCHER.GetModifiedNode(STR_MOD_BY_NAME) }) }, true, null, out firstAdded, out nextAdded);
            var pepSetNew = MATCHER.GetDocModifications(docNew);

            Assert.IsTrue(pepSetNew.StaticModifications.Contains(UniMod.GetModification("Phospho (ST)", true).ChangeExplicit(true)));
            // Update the document to the new settings.
            var pepSetNew1      = pepSetNew;
            var settingsNew2    = docNew.Settings.ChangePeptideModifications(mods => pepSetNew1);
            var lightGlobalMods = new MappedList <string, StaticMod>();

            lightGlobalMods.AddRange(settingsNew2.PeptideSettings.Modifications.StaticModifications);
            var heavyGlobalMods = new MappedList <string, StaticMod>();

            heavyGlobalMods.AddRange(settingsNew2.PeptideSettings.Modifications.AllHeavyModifications);
            // Match again. Test FoundMatches string should now be empty.
            MATCHER.CreateMatches(docNew.Settings.ChangePeptideModifications(mods => pepSetNew1),
                                  new List <string> {
                STR_MOD_BY_NAME
            }, lightGlobalMods, heavyGlobalMods);
            Assert.IsTrue(string.IsNullOrEmpty(MATCHER.FoundMatches));

            // Adding 15N to the settings.
            UpdateMatcher(new[] { carbC }, new[] { LABEL15_N }, null, null);
            // Test sequences with only explicit heavy mods should not have explicit light mods
            Assert.IsNull(MATCHER.GetModifiedNode(STR_HEAVY_ONLY).ExplicitMods.StaticModifications);

            // Test sequences with only explicit light mods should not have explicit heavy mods
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_LIGHT_ONLY).ExplicitMods.HasHeavyModifications);

            // Test global mods take precendence over UniMod
            UpdateMatcher(new[] { carbC }, null, new[] { OXIDATION_M_GLOBAL }, new[] { LABEL15_N });
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_CYS_AND_OXI).ExplicitMods.StaticModifications
                          .Contains(mod => Equals(mod.Modification, OXIDATION_M_GLOBAL)));

            // Test document mods take precendence over UniMod
            UpdateMatcher(new[] { carbC, METHIONINE_OXIDATION }, null, new[] { OXIDATION_M_GLOBAL }, new[] { LABEL15_N });
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_CYS_AND_OXI).HasExplicitMods);

            // Test exception thrown if match doesn't make sense - wrong AA.
            UpdateMatcherFail(STR_FAIL_OX_ON_D);
            // Test exception thrown if match doesn't make sense - wrong terminus.
            _seqs.Add(STR_FAIL_OX_TERM);
            AssertEx.ThrowsException <FormatException>(() => UpdateMatcher(new[] { OXIDATION_M_C_TERM }, null, null, null));
            _seqs.Remove(STR_FAIL_OX_TERM);

            // Heavy 15N - All AAs.
            UpdateMatcher(new[] { carbC, METHIONINE_OXIDATION }, new[] { LABEL15_N }, null, null);
            // Node should be created from document settings if possible.
            Assert.IsNull(MATCHER.GetModifiedNode(STR_HEAVY_15).ExplicitMods);
            // Heavy 15N - specific AA.
            // If only a specific AA is modified, there must be an explicit mod.
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_HEAVY_15_F).HasExplicitMods);

            // Test variable mods match correctly.
            // Put variable mod in global mod and not on doc - make sure don't get variable mod,
            // should get explicit mod in that case.
            var variableMetOx = METHIONINE_OXIDATION.ChangeVariable(true);

            UpdateMatcher(new[] { carbC }, null, new[] { variableMetOx }, null);
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_CYS_AND_OXI).HasExplicitMods);
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_CYS_OXI_PHOS).ExplicitMods.IsVariableStaticMods);
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_CYS_OXI_PHOS_CAP).ExplicitMods.IsVariableStaticMods);
            // Add variable mod to doc
            UpdateMatcher(new[] { carbC, variableMetOx }, null, null, null);
            // Mod can be created by the settings.
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_CYS_AND_OXI).HasExplicitMods);
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_CYS_AND_OXI).ExplicitMods.IsVariableStaticMods);
            // Mod cannot be created by the settings.
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_CYS_OXI_PHOS).ExplicitMods.IsVariableStaticMods);
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_CYS_OXI_PHOS_CAP).ExplicitMods.IsVariableStaticMods);

            // Add Met Ox to global. Test: +16 finds it.
            UpdateMatcher(new[] { carbC }, null, new[] { MET_OX_ROUNDED }, null);
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_CYS_AND_OXI).
                          ExplicitMods.StaticModifications.Contains(mod => Equals(mod.Modification, MET_OX_ROUNDED)));
            // Test: +15.99 finds UniMod.
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_HEAVY_15).
                           ExplicitMods.StaticModifications.Contains(mod => Equals(mod.Modification, MET_OX_ROUNDED)));
            // Add Methionine Oxidation before Met Ox. Test: +16 finds it.
            UpdateMatcher(new[] { carbC }, null, new[] { METHIONINE_OXIDATION, MET_OX_ROUNDED }, null);
            Assert.IsFalse(MATCHER.GetModifiedNode(STR_CYS_AND_OXI).
                           ExplicitMods.StaticModifications.Contains(mod => Equals(mod.Modification, MET_OX_ROUNDED)));
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_CYS_AND_OXI).
                          ExplicitMods.StaticModifications.Contains(mod => Equals(mod.Modification, METHIONINE_OXIDATION)));
            // Test long masses rounded.
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_METOX_LONG_MASS).ExplicitMods.StaticModifications.Contains(mod =>
                                                                                                                 Equals(mod.Modification, METHIONINE_OXIDATION)));
            // Test UniMod label types
            var node = MATCHER.GetModifiedNode(STR_UNIMOD_LABEL);

            Assert.IsNotNull(node);
            Assert.IsNull(node.ExplicitMods.StaticModifications);
            Assert.IsTrue(node.ExplicitMods.HeavyModifications.Contains(mod =>
                                                                        Equals(mod.Modification, N_TERM_LABEL)));
            UpdateMatcherWithNoSequences(new[] { carbC }, new[] { N_TERM_LABEL }, new[] { METHIONINE_OXIDATION, MET_OX_ROUNDED }, null);
            var nodeNew = MATCHER.GetModifiedNode(STR_UNIMOD_LABEL);

            Assert.IsNotNull(nodeNew);
            Assert.IsTrue(nodeNew.TransitionGroups.Any(group => Equals(group.TransitionGroup.LabelType, IsotopeLabelType.heavy)));
            UpdateMatcher(new[] { carbC }, null, new[] { METHIONINE_OXIDATION, MET_OX_ROUNDED }, null);

            // Test case where there are lots of unimod labels
            var nodeUniAll = MATCHER.GetModifiedNode(STR_UNIMOD_ALL);

            Assert.AreEqual(nodeUniAll.ExplicitMods.HeavyModifications.Count, 10);
            Assert.IsNull(nodeUniAll.ExplicitMods.StaticModifications);
            foreach (var mod in nodeUniAll.ExplicitMods.HeavyModifications)
            {
                Assert.AreEqual(mod.Modification.ShortName, "+01");
                Assert.AreEqual(mod.Modification.UnimodId, 994);
            }

            // Test unimod terminal label
            var nodeUniTerm = MATCHER.GetModifiedNode(STR_UNIMOD_TERMINUS);

            Assert.AreEqual(nodeUniTerm.ExplicitMods.HeavyModifications.Count, 1);
            Assert.IsNull(nodeUniTerm.ExplicitMods.StaticModifications);
            Assert.AreEqual(nodeUniTerm.ExplicitMods.HeavyModifications[0].Modification.Terminus, ModTerminus.C);
            Assert.AreEqual(nodeUniTerm.ExplicitMods.HeavyModifications[0].Modification.UnimodId, 298);

            // Basic multi-label test
            var heavyLabelType2 = new IsotopeLabelType("Heavy2", 1);
            var typedMod        = new TypedModifications(heavyLabelType2, new List <StaticMod> {
                LABEL15_N
            });
            var peptideMods = new PeptideModifications(new List <StaticMod>(), new List <TypedModifications> {
                typedMod
            });
            var settingsMultiLabel = SrmSettingsList.GetDefault().ChangePeptideModifications(mods => peptideMods);
            var defSetSetLight     = new MappedList <string, StaticMod>();

            defSetSetLight.AddRange(StaticModList.GetDefaultsOn());
            var defSetHeavy = new MappedList <string, StaticMod>();

            defSetHeavy.AddRange(HeavyModList.GetDefaultsOn());
            defSetHeavy.Add(LABEL15_N);
            MATCHER.CreateMatches(settingsMultiLabel, new List <string> {
                STR_HEAVY_15_F
            }, defSetSetLight, defSetHeavy);
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_HEAVY_15_F).ExplicitMods.GetHeavyModifications().Contains(mod => Equals(mod.LabelType, heavyLabelType2)));
            // Peptide settings should not change.
            var docNew0 = new SrmDocument(settingsMultiLabel).AddPeptideGroups(new[] { new PeptideGroupDocNode(new PeptideGroup(),
                                                                                                               "PepGroup1", "", new[] { MATCHER.GetModifiedNode(STR_HEAVY_15_F) }) }, true, null, out firstAdded, out nextAdded);
            var settingsNew = MATCHER.GetDocModifications(docNew0);

            Assert.AreEqual(settingsMultiLabel.PeptideSettings.Modifications.ChangeHasHeavyModifications(false),
                            settingsNew.ChangeHasHeavyModifications(false));

            // Finding specific modifications.
            // If only specific AA modified, try for most specific modification.
            UpdateMatcher(null, null, null, null, new[] { STR_HEAVY_15_F });
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_HEAVY_15_F)
                          .ExplicitMods.HeavyModifications.Contains(mod =>
                                                                    mod.Modification.AminoAcids.Contains(c => c == 'F')));
            // If only some AAs modified, try for most specific modifications.
            UpdateMatcher(null, null, null, null, new[] { STR_HEAVY_15_NOT_ALL });
            Assert.IsTrue(MATCHER.GetModifiedNode(STR_HEAVY_15_NOT_ALL)
                          .ExplicitMods.HeavyModifications.Contains(mod =>
                                                                    mod.Modification.AminoAcids.Contains(c => c == 'I')));


            using (var testDir = new TestFilesDir(TestContext, ZIP_FILE))
                using (var modMatchDocContainer = InitMatchDocContainer(testDir))
                {
                    var libkeyModMatcher = new LibKeyModificationMatcher();
                    var anlLibSpec       = new BiblioSpecLiteSpec("ANL_Combo", testDir.GetTestPath("ANL_Combined.blib"));
                    var yeastLibSpec     = new BiblioSpecLiteSpec("Yeast", testDir.GetTestPath("Yeast_atlas_small.blib"));
                    modMatchDocContainer.ChangeLibSpecs(new[] { anlLibSpec, yeastLibSpec });
                    var docLibraries  = modMatchDocContainer.Document.Settings.PeptideSettings.Libraries.Libraries;
                    int anlLibIndex   = docLibraries.IndexOf(library => Equals(library.Name, anlLibSpec.Name));
                    int yeastLibIndex = docLibraries.IndexOf(library => Equals(library.Name, yeastLibSpec.Name));

                    libkeyModMatcher.CreateMatches(modMatchDocContainer.Document.Settings,
                                                   docLibraries[anlLibIndex].Keys, defSetSetLight, defSetHeavy);

                    // Test can match 15N
                    Assert.IsTrue(libkeyModMatcher.Matches.Values.Contains(match =>
                                                                           match.HeavyMod != null && match.HeavyMod.Equivalent(LABEL15_N)));

                    var uniModMetOx = UniMod.GetModification("Oxidation (M)", true);

                    // Test can match Met Ox
                    Assert.IsTrue(libkeyModMatcher.Matches.Values.Contains(match =>
                                                                           match.StructuralMod != null && match.StructuralMod.Equivalent(uniModMetOx)));

                    // Test can match 15N and Met ox!
                    Assert.IsTrue(libkeyModMatcher.Matches.Contains(match => match.Key.Mass == 17 &&
                                                                    match.Value.StructuralMod != null && match.Value.StructuralMod.Equivalent(uniModMetOx) &&
                                                                    match.Value.HeavyMod != null && match.Value.HeavyMod.Equivalent(LABEL15_N)));

                    // Test can match Cysteine (Implicit) and Met Ox (variable)
                    libkeyModMatcher.CreateMatches(modMatchDocContainer.Document.Settings,
                                                   docLibraries[yeastLibIndex].Keys, defSetSetLight, defSetHeavy);
                    Assert.IsTrue(libkeyModMatcher.MatcherPepMods.StaticModifications.Contains(mod =>
                                                                                               mod.Formula.Equals(UniMod.GetModification(StaticModList.DEFAULT_NAME, true).Formula) && !mod.IsVariable));
                    Assert.IsTrue(libkeyModMatcher.MatcherPepMods.StaticModifications.Contains(mod =>
                                                                                               mod.Formula.Equals("O") && mod.IsVariable));
                }
        }
Example #3
0
        protected override void DoTest()
        {
            // Create modifications used in this test
            var aquaMod        = new StaticMod("Aqua 13C", "K, R", ModTerminus.C, null, LabelAtoms.C13 | LabelAtoms.N15, null, null);
            var phosphoLossMod = new StaticMod("Phospho Loss", "S, T, Y", null, false, "HPO3",
                                               LabelAtoms.None, RelativeRT.Matching, null, null, new[] { new FragmentLoss("H3PO4"), });
            var multipleLossMod = new StaticMod("Multiple Loss-only", "A", null, false, null,
                                                LabelAtoms.None, RelativeRT.Matching, null, null, new[] { new FragmentLoss("NH3"), new FragmentLoss("H2O") });
            var explicitMassesLossMod = new StaticMod("Explicit Mass Loss", "N", null, false, null,
                                                      LabelAtoms.None, RelativeRT.Matching, null, null, new[] { new FragmentLoss(null, 5, 10) });
            var variableLossMod = new StaticMod("Methionine Oxidized Loss", "M", null, true, "O",
                                                LabelAtoms.None, RelativeRT.Matching, null, null, new[] { new FragmentLoss("CH3O") });

            Settings.Default.HeavyModList.Clear();
            Settings.Default.HeavyModList.Add(aquaMod);
            Settings.Default.StaticModList.Clear();
            Settings.Default.StaticModList.AddRange(StaticModList.GetDefaultsOn());
            Settings.Default.StaticModList.Add(variableLossMod);

            // Bump up the max mz a bit
            var transitionSettingsUI = ShowDialog <TransitionSettingsUI>(SkylineWindow.ShowTransitionSettingsUI);

            RunUI(() =>
            {
                transitionSettingsUI.SelectedTab = TransitionSettingsUI.TABS.Instrument;
                transitionSettingsUI.MaxMz       = 1510;
            });
            OkDialog(transitionSettingsUI, transitionSettingsUI.OkDialog);

            // Bring up add modification dialog
            var peptideSettingsUI = ShowDialog <PeptideSettingsUI>(() =>
                                                                   SkylineWindow.ShowPeptideSettingsUI(PeptideSettingsUI.TABS.Modifications));
            var editModsDlg = ShowEditStaticModsDlg(peptideSettingsUI);
            var addModDlg   = ShowAddModDlg(editModsDlg);

            // Try a few things with new loss UI on the phospho loss modification
            RunUI(() =>
            {
                addModDlg.Modification = phosphoLossMod;
                Assert.IsTrue(addModDlg.GetLossText(0).EndsWith(phosphoLossMod.Losses[0].Formula));
                addModDlg.LossSelectedIndex = 0;
                addModDlg.DeleteLoss();
            });
            // Add back the original loss with the new loss editor dialog
            RunDlg <EditFragmentLossDlg>(addModDlg.AddLoss, dlg =>
            {
                dlg.Loss = phosphoLossMod.Losses[0];
                dlg.OkDialog();
            });
            // Add a smaller formula loss with the new loss editor dialog
            var fragmentLossWater = new FragmentLoss("H2O");

            RunDlg <EditFragmentLossDlg>(addModDlg.AddLoss, dlg =>
            {
                dlg.Loss = fragmentLossWater;
                dlg.OkDialog();
            });
            // Add an explicit mass loss with the new loss editor dialog
            var fragmentLossConstants = new FragmentLoss(null, 20, 25);

            RunDlg <EditFragmentLossDlg>(addModDlg.AddLoss, dlg =>
            {
                dlg.Loss = fragmentLossConstants;
                dlg.OkDialog();
            });
            // Check the added losses, and remove all but the original loss
            RunUI(() =>
            {
                VerifyLossText(addModDlg.GetLossText(0), fragmentLossWater);
                VerifyLossText(addModDlg.GetLossText(1), fragmentLossConstants);
                VerifyLossText(addModDlg.GetLossText(2), phosphoLossMod.Losses[0]);
                addModDlg.LossSelectedIndex = 0;
                addModDlg.DeleteLoss();
                addModDlg.DeleteLoss();
            });
            OkDialog(addModDlg, addModDlg.OkDialog);
            // Add a loss modification with 2 losses and no formula
            RunDlg <EditStaticModDlg>(editModsDlg.AddItem, dlg =>
            {
                dlg.Modification = multipleLossMod;
                VerifyLossText(dlg.GetLossText(0), multipleLossMod.Losses[0]);
                VerifyLossText(dlg.GetLossText(1), multipleLossMod.Losses[1]);
                dlg.OkDialog();
            });
            // Add a loss modification with explicit numeric losses and no formula
            // starting with no losses
            var addExplicitLossDlg = ShowAddModDlg(editModsDlg);

            RunUI(() =>
            {
                addExplicitLossDlg.Modification = explicitMassesLossMod;
                addExplicitLossDlg.ShowLoss     = true;
                VerifyLossText(addExplicitLossDlg.GetLossText(0), explicitMassesLossMod.Losses[0]);
                addExplicitLossDlg.LossSelectedIndex = 0;
                addExplicitLossDlg.DeleteLoss();
            });
            // Add the explicit numeric loss
            RunDlg <EditFragmentLossDlg>(addExplicitLossDlg.AddLoss, dlg =>
            {
                dlg.Loss = fragmentLossConstants;
                dlg.OkDialog();
            });
            OkDialog(addExplicitLossDlg, addExplicitLossDlg.OkDialog);
            OkDialog(editModsDlg, editModsDlg.OkDialog);
            // Check the phospho loss modification
            RunUI(() => peptideSettingsUI.PickedStaticMods =
                      new List <string>(peptideSettingsUI.PickedStaticMods)
            {
                phosphoLossMod.Name
            }.ToArray());
            WaitForOpenForm <PeptideSettingsUI>(); // Show Modifications tab for form testing
            OkDialog(peptideSettingsUI, peptideSettingsUI.OkDialog);

            // Add FASTA sequence
            RunUI(() => SkylineWindow.Paste(TEXT_FASTA_YEAST_7));
            // Losses not added by default without a library
            Assert.AreEqual(0, GetLossCount(SkylineWindow.Document, 1));

            // Make sure setting losses as included Always works
            {
                var docBeforeAlways         = SkylineWindow.Document;
                var peptideSettingsUIAlways = ShowDialog <PeptideSettingsUI>(() =>
                                                                             SkylineWindow.ShowPeptideSettingsUI(PeptideSettingsUI.TABS.Modifications));
                var editModsDlgAlways = ShowEditStaticModsDlg(peptideSettingsUIAlways);
                RunUI(() => editModsDlgAlways.SelectItem(phosphoLossMod.Name));
                var editModDlgAlways = ShowDialog <EditStaticModDlg>(editModsDlgAlways.EditItem);
                RunUI(() => editModDlgAlways.LossSelectedIndex = 0);
                RunDlg <EditFragmentLossDlg>(editModDlgAlways.EditLoss, dlg =>
                {
                    dlg.Inclusion = LossInclusion.Always;
                    dlg.OkDialog();
                });
                OkDialog(editModDlgAlways, editModDlgAlways.OkDialog);
                OkDialog(editModsDlgAlways, editModsDlgAlways.OkDialog);
                OkDialog(peptideSettingsUIAlways, peptideSettingsUIAlways.OkDialog);
                var docAfterAlways = WaitForDocumentChange(docBeforeAlways);
                Assert.AreEqual(5, GetLossCount(docAfterAlways, 1));
                AssertEx.Serializable(docAfterAlways);
                // Undo and revert to original phospo loss modification definition
                RunUI(SkylineWindow.Undo);
                Settings.Default.StaticModList.SetValue(phosphoLossMod);
            }

            // Show losses in the pick list
            var docFasta = WaitForProteinMetadataBackgroundLoaderCompletedUI();

            SelectNode(SrmDocument.Level.TransitionGroups, 0);
            RunDlg <PopupPickList>(SkylineWindow.ShowPickChildrenInTest, dlg =>
            {
                dlg.ApplyFilter(false);
                var losses = GetLossGroups(dlg.ItemNames).ToArray();
                Assert.AreEqual(1, losses.Length);
                VerifyLossGroup(losses, 0, 98, 124);
                dlg.ToggleFind();
                dlg.SearchString = "-98";
                dlg.ToggleItem(0);
                dlg.ToggleItem(1);
                dlg.OnOk();
            });
            var docLoss = WaitForDocumentChange(docFasta);

            // Make sure two losses were added
            Assert.AreEqual(2, GetLossCount(docLoss, 1));

            // Allow 2 neutral losses per fragment
            RunDlg <PeptideSettingsUI>(SkylineWindow.ShowPeptideSettingsUI, dlg =>
            {
                dlg.MaxNeutralLosses = 2;
                dlg.OkDialog();
            });

            var docLoss2 = WaitForDocumentChange(docLoss);

            // Make sure 2 phospho losses are now possible
            IGrouping <double, string>[] losses1 = null;
            RunDlg <PopupPickList>(SkylineWindow.ShowPickChildrenInTest, dlg =>
            {
                dlg.ApplyFilter(false);
                losses1 = GetLossGroups(dlg.ItemNames).ToArray();
                Assert.AreEqual(2, losses1.Length);
                VerifyLossGroup(losses1, 0, 98, 124);
                VerifyLossGroup(losses1, 1, 196, 109);
                dlg.OnCancel();
            });

            // Add a modification with multiple possible losses
            RunDlg <PeptideSettingsUI>(SkylineWindow.ShowPeptideSettingsUI, dlg =>
            {
                dlg.PickedStaticMods = new List <string>(dlg.PickedStaticMods)
                {
                    multipleLossMod.Name
                }.ToArray();
                dlg.OkDialog();
            });

            var docLossMulti = WaitForDocumentChange(docLoss2);

            // Make sure all combinations of 2 except 2 of the multiple
            // losses are possible, since only one amino acid A exists in this
            // peptide.
            RunDlg <PopupPickList>(SkylineWindow.ShowPickChildrenInTest, dlg =>
            {
                dlg.ApplyFilter(false);
                var losses = GetLossGroups(dlg.ItemNames).ToArray();
                Assert.AreEqual(6, losses.Length);
                VerifyLossGroup(losses, 0, 17, 66);
                VerifyLossGroup(losses, 1, 18, 66);
                VerifyLossGroup(losses, 2, 98, 124);
                VerifyLossGroup(losses, 3, 115, 61);
                VerifyLossGroup(losses, 4, 116, 61);
                VerifyLossGroup(losses, 5, 196, 109);
                AssertEx.NoDiff(TextUtil.LineSeparate(losses1[0].ToArray()), TextUtil.LineSeparate(losses[2].ToArray()));
                AssertEx.NoDiff(TextUtil.LineSeparate(losses1[1].ToArray()), TextUtil.LineSeparate(losses[5].ToArray()));
                // Add new neutral loss transitions to the document
                dlg.ToggleFind();
                dlg.SearchString = "-17]";
                dlg.ToggleItem(0);
                dlg.SearchString = "-115]";
                dlg.ToggleItem(0);
                dlg.OnOk();
            });

            var docLossMultiAdded = WaitForDocumentChange(docLossMulti);

            Assert.AreEqual(1, GetLossCount(docLossMultiAdded, 2));

            // Add heavy modifications and make sure transition group is added with losses
            RunDlg <PeptideSettingsUI>(SkylineWindow.ShowPeptideSettingsUI, dlg =>
            {
                dlg.PickedHeavyMods = new[] { aquaMod.Name };
                dlg.OkDialog();
            });

            var docLossMultiHeavy = WaitForDocumentChange(docLossMultiAdded);

            Assert.AreEqual(4, docLossMultiHeavy.PeptideTransitionGroupCount);
            Assert.AreEqual(8, GetLossCount(docLossMultiHeavy, 1));
            Assert.AreEqual(2, GetLossCount(docLossMultiHeavy, 2));

            // Make sure this document is serializable
            AssertEx.Serializable(docLossMultiHeavy, AssertEx.DocumentCloned);

            // Reset to just 1 neutral loss per fragment, and turn off heavy mod
            RunDlg <PeptideSettingsUI>(SkylineWindow.ShowPeptideSettingsUI, dlg =>
            {
                dlg.PickedHeavyMods  = new string[0];
                dlg.MaxNeutralLosses = 1;
                dlg.OkDialog();
            });

            var docLossMulti1 = WaitForDocumentChange(docLossMultiHeavy);

            Assert.AreEqual(3, GetLossCount(docLossMulti1, 1));
            Assert.AreEqual(0, GetLossCount(docLossMulti1, 2));

            // Remove all neutral loss modifications currently on the document
            // and add the constant numeric loss
            RunDlg <PeptideSettingsUI>(SkylineWindow.ShowPeptideSettingsUI, dlg =>
            {
                dlg.PickedStaticMods = new[] { explicitMassesLossMod.Name };
                dlg.OkDialog();
            });

            var docNoLoss2 = WaitForDocumentChange(docLossMulti1);

            Assert.AreEqual(0, GetLossCount(docNoLoss2, 1));

            // Add a neutral loss transition with constant numeric loss
            RunDlg <PopupPickList>(SkylineWindow.ShowPickChildrenInTest, dlg =>
            {
                dlg.ApplyFilter(false);
                var losses = GetLossGroups(dlg.ItemNames).ToArray();
                Assert.AreEqual(1, losses.Length);
                VerifyLossGroup(losses, 0, 20, 85);
                // Add new neutral loss transitions to the document
                dlg.ToggleFind();
                dlg.SearchString = "-20";
                dlg.ToggleItem(0);
                dlg.OnOk();
            });

            // Verify that the expected loss was added to the document
            var docConstantMono = WaitForDocumentChange(docNoLoss2);

            Assert.AreEqual(1, GetLossCount(docConstantMono, 1));
            var pathTranLoss = docConstantMono.GetPathTo((int)SrmDocument.Level.Transitions, 0);
            var nodeTranLos  = (TransitionDocNode)docConstantMono.FindNode(pathTranLoss);

            Assert.AreEqual(IonType.precursor.GetLocalizedString() + " -20", nodeTranLos.FragmentIonName);

            // Switch mass type to average
            RunDlg <TransitionSettingsUI>(SkylineWindow.ShowTransitionSettingsUI, dlg =>
            {
                dlg.FragmentMassType = MassType.Average;
                dlg.OkDialog();
            });

            // Make sure neutral loss changes as expected
            var docConstantAverage = WaitForDocumentChange(docConstantMono);

            Assert.AreEqual(1, GetLossCount(docConstantAverage, 1));
            nodeTranLos = (TransitionDocNode)docConstantAverage.FindNode(pathTranLoss);
            Assert.AreEqual(IonType.precursor.GetLocalizedString() + " -25", nodeTranLos.FragmentIonName);

            // Make sure the resulting document is serializable
            AssertEx.Serializable(docConstantAverage, AssertEx.DocumentCloned);
        }
        protected override void DoTest()
        {
            // Clean-up before running the test
            RunUI(() => SkylineWindow.ModifyDocument("Set default settings",
                                                     doc => doc.ChangeSettings(SrmSettingsList.GetDefault())));

            Settings.Default.HeavyModList.Clear();
            Settings.Default.StaticModList.Clear();
            Settings.Default.StaticModList.AddRange(StaticModList.GetDefaultsOn());

            // Show dialog asking user if text is FASTA or peptide list
            RunDlg <PasteTypeDlg>(() => SkylineWindow.Paste(TextUtil.LineSeparate("QFVLSCVILQFVLSCVILQFVLSCVILQFVLSCVILR",
                                                                                  "DIEVYCDGAITTKDIEVYCDGAITTKDIEVYCDGAITTK")),
                                  dlg => dlg.CancelDialog());

            // Add two peptides
            const string pepSequence1 = "QFVLSCVILR";
            const string pepSequence2 = "DIEVYCDGAITTK";

            RunUI(() => SkylineWindow.Paste(string.Join("\n", new[] { pepSequence1, pepSequence2 })));

            // Check and save original document information
            var docOrig         = WaitForProteinMetadataBackgroundLoaderCompletedUI();
            var pathPeptide     = docOrig.GetPathTo((int)SrmDocument.Level.Molecules, 1);
            var peptideImplicit = (PeptideDocNode)docOrig.FindNode(pathPeptide);

            Assert.AreEqual(1, peptideImplicit.Children.Count);
            Assert.IsNull(peptideImplicit.ExplicitMods);

            // Add a new static modification on cysteine
            var peptideSettingsUI = ShowPeptideSettings();
            var modStatic         = new StaticMod("Another Cysteine", "C", null, "CO8N2");

            AddStaticMod(modStatic, peptideSettingsUI);
            RunUI(peptideSettingsUI.OkDialog);
            WaitForClosedForm(peptideSettingsUI);

            // Select the peptide of interest
            RunUI(() => SkylineWindow.SequenceTree.SelectedPath = pathPeptide);

            Assert.AreSame(docOrig, SkylineWindow.Document);

            // Explicitly add the new modification
            var modifyPeptideDlg = ShowModifyPeptide();

            RunUI(() =>
            {
                modifyPeptideDlg.SelectModification(IsotopeLabelType.light,
                                                    pepSequence2.IndexOf('C'), modStatic.Name);
                modifyPeptideDlg.OkDialog();
            });

            // Check for correct response to modification
            var docExplicit     = WaitForDocumentChange(docOrig);
            var peptideExplicit = (PeptideDocNode)docExplicit.FindNode(pathPeptide);

            Assert.AreEqual(1, peptideExplicit.Children.Count);
            // Precursor m/z value should have increased
            Assert.IsTrue(((TransitionGroupDocNode)peptideExplicit.Children[0]).PrecursorMz >
                          ((TransitionGroupDocNode)peptideImplicit.Children[0]).PrecursorMz);

            var mods = peptideExplicit.ExplicitMods;

            Assert.IsNotNull(mods);
            Assert.IsTrue(mods.IsModified(IsotopeLabelType.light));
            // Heavy should not be explicitly modified
            Assert.IsFalse(mods.IsModified(IsotopeLabelType.heavy));

            // Add new label types
            peptideSettingsUI = ShowPeptideSettings();
            string[] heavyLabelNames = { "heavy AA", "heavy All" };
            SetHeavyLabelNames(peptideSettingsUI, heavyLabelNames);

            // Make sure label type list edit worked
            IsotopeLabelType[] heavyLabelTypes = peptideSettingsUI.LabelTypes.ToArray();
            Assert.AreEqual(2, heavyLabelTypes.Length);
            var labelTypeAa  = heavyLabelTypes[0];
            var labelTypeAll = heavyLabelTypes[1];

            Assert.AreEqual(heavyLabelNames.Length, heavyLabelTypes.Length);
            for (int i = 0; i < heavyLabelTypes.Length; i++)
            {
                Assert.AreEqual(heavyLabelNames[i], heavyLabelTypes[i].Name);
            }

            // Add new heavy modifications
            var mod15N = new StaticMod("Label:15N", null, null, null, LabelAtoms.N15, null, null);

            AddHeavyMod(mod15N, peptideSettingsUI);
//            var mod13C = new StaticMod("All 13C", null, null, null, LabelAtoms.C13, null, null);
//            AddHeavyMod(mod13C, peptideSettingsUI);
            var modK13C = new StaticMod("Label:13C(6) (C-term K)", "K", ModTerminus.C, null, LabelAtoms.C13, null, null);

            AddHeavyMod(modK13C, peptideSettingsUI);
            var modR13C = new StaticMod("Label:13C(6) (C-term R)", "R", ModTerminus.C, null, LabelAtoms.C13, null, null);

            AddHeavyMod(modR13C, peptideSettingsUI);
            var modV13C = new StaticMod("Label:13C(5)15N(1) (V)", "V", null, null, LabelAtoms.C13 | LabelAtoms.N15, null, null);

            AddHeavyMod(modV13C, peptideSettingsUI);

            // Set heavy modification for the peptides
            RunUI(() =>
            {
                peptideSettingsUI.SelectedLabelTypeName = heavyLabelNames[1];
                peptideSettingsUI.PickedHeavyMods       = new[] { mod15N.Name };
                peptideSettingsUI.SelectedLabelTypeName = heavyLabelNames[0];
                peptideSettingsUI.PickedHeavyMods       = new[] { modK13C.Name, modR13C.Name };
                peptideSettingsUI.OkDialog();
            });

            // Make sure the document was updated as expected.  Explicit modification
            // should not keep new types from adding precursors to both peptides.
            var docMultiType = WaitForDocumentChange(docExplicit);

            foreach (var nodePep in docMultiType.Peptides)
            {
                Assert.AreEqual(3, nodePep.Children.Count);
                TransitionGroupDocNode nodeGroupLast = null;
                foreach (TransitionGroupDocNode nodeGroup in nodePep.Children)
                {
                    if (nodeGroupLast != null)
                    {
                        Assert.IsTrue(nodeGroup.PrecursorMz > nodeGroupLast.PrecursorMz);
                    }
                    nodeGroupLast = nodeGroup;

                    var labelType = nodeGroup.TransitionGroup.LabelType;
                    if (!labelType.IsLight)
                    {
                        Assert.IsTrue(heavyLabelTypes.Contains(labelType));
                    }
                }
            }

            // Get the modified peptide in the new document
            peptideExplicit = (PeptideDocNode)docMultiType.FindNode(pathPeptide);

            // Explicitly set the heavy All modification to match the heavy AA modification
            var modifyPeptideMultiDlg = ShowModifyPeptide();

            RunUI(() =>
            {
                for (int i = 0; i < pepSequence2.Length - 1; i++)
                {
                    modifyPeptideMultiDlg.SelectModification(labelTypeAll, i, "");
                }
                modifyPeptideMultiDlg.SelectModification(labelTypeAll, pepSequence2.Length - 1, modK13C.Name);
                modifyPeptideMultiDlg.OkDialog();
            });

            // Make sure both heavy types have precursor m/z value that match the original
            var docModMatch  = WaitForDocumentChange(docMultiType);
            var peptideMatch = (PeptideDocNode)docModMatch.FindNode(pathPeptide);

            AssertPrecursorMzAreEqaul(peptideExplicit, 1, peptideMatch, 1);
            AssertPrecursorMzAreEqaul(peptideExplicit, 1, peptideMatch, 2);

            // Remove the modification on K for heavyAA, and make sure this gets rid of the precursor
            var modifyPeptideEmptyDlg = ShowModifyPeptide();

            RunUI(() =>
            {
                modifyPeptideEmptyDlg.SelectModification(labelTypeAa, pepSequence2.Length - 1, "");
                modifyPeptideEmptyDlg.OkDialog();
            });
            var docModRemoved  = WaitForDocumentChange(docModMatch);
            var peptideRemoved = (PeptideDocNode)docModRemoved.FindNode(pathPeptide);

            Assert.AreEqual(2, peptideRemoved.Children.Count);

            // Reset the modifications
            var modifyPeptideResetDlg = ShowModifyPeptide();

            RunUI(() =>
            {
                modifyPeptideResetDlg.ResetMods();
                modifyPeptideResetDlg.OkDialog();
            });

            // Make sure this removes the explicit modification and adds back the removed precursor
            var docModReset = WaitForDocumentChange(docModRemoved);

            peptideImplicit = (PeptideDocNode)docModReset.FindNode(pathPeptide);
            Assert.IsNull(peptideImplicit.ExplicitMods);
            Assert.AreEqual(3, peptideImplicit.Children.Count);

            // Explicitly set the heavy All modification to match the heavy AA modification
            var modifyPeptideMatchDlg = ShowModifyPeptide();

            RunUI(() =>
            {
                for (int i = 0; i < pepSequence2.Length - 1; i++)
                {
                    modifyPeptideMatchDlg.SelectModification(labelTypeAll, i, "");
                }
                modifyPeptideMatchDlg.SelectModification(labelTypeAll, pepSequence2.Length - 1, modK13C.Name);
                modifyPeptideMatchDlg.OkDialog();
            });
            var docModAA = WaitForDocumentChange(docModReset);

            // Change implicit static modification and heavy AA
            var peptideSettingsUIChange = ShowPeptideSettings();

            RunUI(() =>
            {
                peptideSettingsUIChange.PickedStaticMods = new[] { modStatic.Name };
                peptideSettingsUIChange.PickedHeavyMods  = new[] { modV13C.Name };
                peptideSettingsUIChange.OkDialog();
            });
            var docModImplicitStatic = WaitForDocumentChange(docModAA);
            var peptideMatch2        = (PeptideDocNode)docModImplicitStatic.FindNode(pathPeptide);

            Assert.IsNotNull(peptideMatch2.ExplicitMods);
            Assert.IsFalse(peptideMatch2.ExplicitMods.IsModified(heavyLabelTypes[0]));
            Assert.IsTrue(peptideMatch2.ExplicitMods.IsModified(heavyLabelTypes[1]));
            AssertPrecursorMzAreEqaul(peptideMatch, 0, peptideMatch2, 0);
            AssertPrecursorMzAreNotEqaul(peptideMatch, 1, peptideMatch2, 1);
            AssertPrecursorMzAreEqaul(peptideMatch, 2, peptideMatch2, 2);

            // Remove the heavy All type, which should remove the only explicit modification
            var peptideSettingsUIRemove = ShowPeptideSettings();

            SetHeavyLabelNames(peptideSettingsUIRemove, new[] { heavyLabelNames[0] });
            RunUI(peptideSettingsUIRemove.OkDialog);

            var docModRemoveType = WaitForDocumentChange(docModImplicitStatic);

            foreach (var nodePep in docModRemoveType.Peptides)
            {
                Assert.IsNull(nodePep.ExplicitMods);
                Assert.AreEqual(2, nodePep.Children.Count);
            }

            // Undo, and add an explicit modification to the heavy AA type
            RunUI(SkylineWindow.Undo);
            Assert.AreSame(docModImplicitStatic, SkylineWindow.Document);

            var modifyPeptideAADlg = ShowModifyPeptide();

            RunUI(() =>
            {
                modifyPeptideAADlg.SelectModification(labelTypeAa, pepSequence2.IndexOf('V'), "");
                modifyPeptideAADlg.SelectModification(labelTypeAa, pepSequence2.Length - 1, modK13C.Name);
                modifyPeptideAADlg.OkDialog();
            });
            var docModExplicitStatic = WaitForDocumentChange(docModImplicitStatic);

            // Remove the heavy All label type again
            peptideSettingsUIRemove = ShowPeptideSettings();
            SetHeavyLabelNames(peptideSettingsUIRemove, new[] { heavyLabelNames[0] });
            OkDialog(peptideSettingsUIRemove, peptideSettingsUIRemove.OkDialog);

            var docMultiExplicit     = WaitForDocumentChange(docModExplicitStatic);
            var peptideStillExplicit = (PeptideDocNode)docMultiExplicit.FindNode(pathPeptide);

            Assert.IsNotNull(peptideStillExplicit.ExplicitMods);
            Assert.IsTrue(peptideStillExplicit.ExplicitMods.IsModified(labelTypeAa));
            Assert.IsFalse(peptideStillExplicit.ExplicitMods.IsModified(labelTypeAll));
            AssertPrecursorMzAreEqaul(peptideMatch, 1, peptideStillExplicit, 1);
        }
        protected override void DoTest()
        {
            // Create modifications used in this test
            var aquaMods = new[]
            {
                new StaticMod("Heavy K", "K", ModTerminus.C, null, LabelAtoms.C13 | LabelAtoms.N15, null, null),
                new StaticMod("Heavy R", "R", ModTerminus.C, null, LabelAtoms.C13 | LabelAtoms.N15, null, null)
            };
            var explicitMod = new StaticMod("13C L", "L", null, null, LabelAtoms.C13, null, null);
            var variableMod = new StaticMod("Methionine Oxidized", "M", null, true, "O",
                                            LabelAtoms.None, RelativeRT.Matching, null, null, null);

            Settings.Default.HeavyModList.Clear();
            Settings.Default.HeavyModList.AddRange(aquaMods);
            Settings.Default.HeavyModList.Add(explicitMod);
            Settings.Default.StaticModList.Clear();
            Settings.Default.StaticModList.AddRange(StaticModList.GetDefaultsOn());
            var carbMod = Settings.Default.StaticModList[0];

            Settings.Default.StaticModList.Add(variableMod);

            // Clean-up before running the test
            var settings = SrmSettingsList.GetDefault().ChangePeptideModifications(mod =>
                                                                                   mod.ChangeHeavyModifications(aquaMods));

            RunUI(() => SkylineWindow.ModifyDocument("Set test settings",
                                                     doc => doc.ChangeSettings(settings)));

            // Add FASTA sequence
            RunUI(() => SkylineWindow.Paste(TEXT_FASTA_YEAST_39));

            // Check and save original document information
            var docOrig     = WaitForProteinMetadataBackgroundLoaderCompletedUI();
            var pathPeptide = docOrig.GetPathTo((int)SrmDocument.Level.Molecules, docOrig.PeptideCount - 3);
            var peptideOrig = (PeptideDocNode)docOrig.FindNode(pathPeptide);

            Assert.AreEqual(2, peptideOrig.Children.Count);
            Assert.IsNull(peptideOrig.ExplicitMods);

            // Add methionine oxidation variable modification
            SetStaticModifications(names => new List <string>(names)
            {
                variableMod.Name
            });
            var docVarMod = WaitForDocumentChange(docOrig);

            // Check that variable modification worked, and that the peptide of
            // interest is variably modified.
            Assert.IsTrue(docOrig.PeptideCount < docVarMod.PeptideCount);
            pathPeptide = docVarMod.GetPathTo((int)SrmDocument.Level.Molecules, docVarMod.PeptideCount - 4);
            var peptideVarMod = (PeptideDocNode)docVarMod.FindNode(pathPeptide);

            Assert.AreEqual(2, peptideVarMod.Children.Count);
            Assert.IsTrue(peptideVarMod.HasVariableMods,
                          string.Format("No variable modifications found on the peptide {0}", peptideVarMod.Peptide.Sequence));
            Assert.IsFalse(peptideVarMod.ExplicitMods.IsModified(IsotopeLabelType.heavy));
            AssertPrecursorMzIsModified(peptideVarMod, 0, peptideVarMod, 1, -5, 0.2);

            // Select the peptide of interest
            RunUI(() => SkylineWindow.SequenceTree.SelectedPath = pathPeptide);

            // Make sure the explicit modifications dialog does not modify the
            // peptide when nothing is changed.
            string sequence = peptideVarMod.Peptide.Sequence;

            RunDlg <EditPepModsDlg>(SkylineWindow.ModifyPeptide, dlg =>
            {
                for (int i = 0; i < sequence.Length; i++)
                {
                    dlg.SelectModification(IsotopeLabelType.light, i, "");
                    dlg.SelectModification(IsotopeLabelType.heavy, i, "");
                }
                dlg.ResetMods();
                dlg.OkDialog();
            });
            Assert.AreSame(docVarMod, SkylineWindow.Document);

            // Explicitly change the heavy modification
            RunDlg <EditPepModsDlg>(SkylineWindow.ModifyPeptide, dlg =>
            {
                dlg.SelectModification(IsotopeLabelType.heavy, sequence.Length - 1, "");
                dlg.SelectModification(IsotopeLabelType.heavy, sequence.LastIndexOf('L'),
                                       explicitMod.Name);
                dlg.OkDialog();
            });

            // Check for correct response to modification
            var docExplicit     = WaitForDocumentChange(docOrig);
            var peptideExplicit = (PeptideDocNode)docExplicit.FindNode(pathPeptide);

            Assert.AreEqual(2, peptideExplicit.Children.Count);
            // Precursor m/z for light should be same
            AssertPrecursorMzAreEqaul(peptideVarMod, 0, peptideExplicit, 0);
            // Heavy should have changed
            AssertPrecursorMzIsModified(peptideExplicit, 0, peptideExplicit, 1, -3, 0.2);
            // Heavy should now be explicitly modified
            Assert.IsTrue(peptideExplicit.ExplicitMods.IsModified(IsotopeLabelType.heavy));

            // Remove carbamidomethyl cysteine implicit modification
            SetStaticModifications(names => new[] { variableMod.Name });
            var docNoImplicit     = WaitForDocumentChange(docExplicit);
            var peptideNoImplicit = (PeptideDocNode)docNoImplicit.FindNode(pathPeptide);
            // Light should have gotten 57.0 lighter
            const double modCarbMz = 57.0 / 2;

            AssertPrecursorMzIsModified(peptideExplicit, 0, peptideNoImplicit, 0, modCarbMz, 0.1);
            // Heavy delta should not have changed
            AssertPrecursorMzIsModified(peptideNoImplicit, 0, peptideNoImplicit, 1, -3, 0.2);

            // Reset should still return to implicit heavy mods without removing
            // variable mods.
            RunDlg <EditPepModsDlg>(SkylineWindow.ModifyPeptide, dlg =>
            {
                dlg.ResetMods();
                dlg.OkDialog();
            });
            var docReset     = WaitForDocumentChange(docNoImplicit);
            var peptideReset = (PeptideDocNode)docReset.FindNode(pathPeptide);

            Assert.IsTrue(peptideReset.HasExplicitMods);
            Assert.IsFalse(peptideReset.ExplicitMods.IsModified(IsotopeLabelType.heavy));
            AssertPrecursorMzIsModified(peptideReset, 0, peptideReset, 1, -5, 0.2);

            // Explicitly add back the Carbamidomethyl Cysteine
            // Reset should still return to implicit heavy mods
            RunDlg <EditPepModsDlg>(SkylineWindow.ModifyPeptide, dlg =>
            {
                dlg.SelectModification(IsotopeLabelType.light, sequence.IndexOf('C'), carbMod.Name);
                dlg.OkDialog();
            });
            var docExCarb     = WaitForDocumentChange(docReset);
            var peptideExCarb = (PeptideDocNode)docExCarb.FindNode(pathPeptide);

            Assert.IsTrue(peptideExCarb.HasExplicitMods);
            Assert.IsFalse(peptideExCarb.HasVariableMods);
            AssertPrecursorMzAreEqaul(peptideVarMod, 0, peptideExCarb, 0);
            AssertPrecursorMzAreEqaul(peptideVarMod, 1, peptideExCarb, 1);

            // Reset at this point should completely remove explicit modifications
            // including oxidized M.
            RunDlg <EditPepModsDlg>(SkylineWindow.ModifyPeptide, dlg =>
            {
                dlg.ResetMods();
                dlg.OkDialog();
            });
            var docResetImplicit     = WaitForDocumentChange(docExCarb);
            var peptideResetImplicit = (PeptideDocNode)docResetImplicit.FindNode(pathPeptide);

            Assert.IsFalse(peptideResetImplicit.HasExplicitMods);
            AssertPrecursorMzIsModified(peptideOrig, 0, peptideResetImplicit, 0, modCarbMz, 0.1);
            AssertPrecursorMzIsModified(peptideOrig, 1, peptideResetImplicit, 1, modCarbMz, 0.1);

            // Turn off the variable modifications and explicitly modify using a variable mod
            RunDlg <PeptideSettingsUI>(SkylineWindow.ShowPeptideSettingsUI, dlg =>
            {
                dlg.PickedStaticMods = new string[0];
                dlg.OkDialog();
            });

            var docNoStaticMods = WaitForDocumentChange(docResetImplicit);

            // Explicitly modify the first peptide
            var pathPeptideFirst = docNoStaticMods.GetPathTo((int)SrmDocument.Level.Molecules, 0);
            var peptideUnmod     = (PeptideDocNode)docNoStaticMods.FindNode(pathPeptideFirst);

            RunUI(() => SkylineWindow.SelectedPath = pathPeptideFirst);
            RunDlg <EditPepModsDlg>(SkylineWindow.ModifyPeptide, dlg =>
            {
                var sequenceUnmod = peptideUnmod.Peptide.Sequence;
                dlg.SelectModification(IsotopeLabelType.light, sequenceUnmod.IndexOf('M'), variableMod.Name);
                dlg.OkDialog();
            });

            var docExplicitVarMod     = WaitForDocumentChange(docNoStaticMods);
            var peptideExplicitVarMod = (PeptideDocNode)docExplicitVarMod.FindNode(pathPeptideFirst);

            Assert.IsTrue(peptideExplicitVarMod.HasExplicitMods);
            if (peptideExplicitVarMod.ExplicitMods.StaticModifications == null)
            {
                Assert.IsNotNull(peptideExplicitVarMod.ExplicitMods.StaticModifications);
                return; // For ReSharper
            }
            var varModPeptide = peptideExplicitVarMod.ExplicitMods.StaticModifications[0].Modification;

            Assert.AreEqual(variableMod.Name, varModPeptide.Name);
            // The modification instance on the peptide should not be marked as variable
            Assert.IsFalse(varModPeptide.IsVariable);
            var varModSettings = docExplicitVarMod.Settings.PeptideSettings.Modifications.StaticModifications[0];

            Assert.AreEqual(variableMod.Name, varModSettings.Name);
            Assert.IsTrue(varModSettings.IsExplicit);
            Assert.IsFalse(varModSettings.IsVariable);

            // Make sure this did not turn on the variable modification in the settings UI
            RunDlg <PeptideSettingsUI>(SkylineWindow.ShowPeptideSettingsUI, dlg =>
            {
                Assert.AreEqual(0, dlg.PickedStaticMods.Length);
                dlg.OkDialog();
            });

            Directory.CreateDirectory(TestContext.TestDir);
            string saveFilePath = TestContext.GetTestPath("TestExplicitVariable.sky");

            WaitForProteinMetadataBackgroundLoaderCompletedUI(); // make sure doc is complete before save

            RunUI(() =>
            {
                Assert.IsTrue(SkylineWindow.SaveDocument(saveFilePath));
                SkylineWindow.NewDocument();
                Assert.IsTrue(SkylineWindow.OpenFile(saveFilePath));
            });

            WaitForProteinMetadataBackgroundLoaderCompletedUI();
            var docRestored              = SkylineWindow.Document;
            var pathPeptideFirstNew      = docRestored.GetPathTo((int)SrmDocument.Level.Molecules, 0);
            var peptideExplicitVarModNew = docRestored.FindNode(pathPeptideFirstNew);

            Assert.AreEqual(peptideExplicitVarMod, peptideExplicitVarModNew,
                            "Saved peptide with explicit variable modification was not restored correctly.");
            Assert.IsTrue(Settings.Default.StaticModList.Contains(variableMod),
                          "Expected variable modification has been removed from the global list.");
        }