Example #1
0
        public int GetUniqueUINameOfProject(IVsHierarchy pHierarchy, out string pbstrUniqueName)
        {
            MockIVsProject project = pHierarchy as MockIVsProject;

            pbstrUniqueName = "Unique name of " + project.ProjectFile;
            return(VSConstants.S_OK);
        }
Example #2
0
 public void AddProject(MockIVsProject project)
 {
     if (_solutionFile != null)
     {
         _projects.Add(project);
         foreach (IVsSolutionEvents sink in _eventSinks)
         {
             if (sink != null)
             {
                 sink.OnAfterOpenProject(project, 1);
             }
         }
     }
 }
Example #3
0
 public void AddProject(MockIVsProject project)
 {
     if (_solutionFile != null)
     {
         _projects.Add(project);
         foreach (IVsSolutionEvents sink in _eventSinks)
         {
             if (sink != null)
             {
                 sink.OnAfterOpenProject(project, 1);
             }
         }
     }
 }
        public void TestSccMenuCommands()
        {
            int  result       = 0;
            Guid badGuid      = new Guid();
            Guid guidCmdGroup = GuidList.guidSccProviderCmdSet;

            OLECMD[] cmdAddToScc = new OLECMD[1];
            cmdAddToScc[0].cmdID = CommandId.icmdAddToSourceControl;
            OLECMD[] cmdCheckin = new OLECMD[1];
            cmdCheckin[0].cmdID = CommandId.icmdCheckin;
            OLECMD[] cmdCheckout = new OLECMD[1];
            cmdCheckout[0].cmdID = CommandId.icmdCheckout;
            OLECMD[] cmdUseSccOffline = new OLECMD[1];
            cmdUseSccOffline[0].cmdID = CommandId.icmdUseSccOffline;
            OLECMD[] cmdViewToolWindow = new OLECMD[1];
            cmdViewToolWindow[0].cmdID = CommandId.icmdViewToolWindow;
            OLECMD[] cmdToolWindowToolbarCommand = new OLECMD[1];
            cmdToolWindowToolbarCommand[0].cmdID = CommandId.icmdToolWindowToolbarCommand;
            OLECMD[] cmdUnsupported = new OLECMD[1];
            cmdUnsupported[0].cmdID = 0;

            // Initialize the provider, etc
            SccProviderService target = GetSccProviderServiceInstance;

            // Mock a service implementing IVsMonitorSelection
            BaseMock monitorSelection = MockIVsMonitorSelectionFactory.GetMonSel();

            serviceProvider.AddService(typeof(IVsMonitorSelection), monitorSelection, true);

            // Commands that don't belong to our package should not be supported
            result = _sccProvider.QueryStatus(ref badGuid, 1, cmdAddToScc, IntPtr.Zero);
            Assert.AreEqual((int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED, result);

            // The command should be invisible when there is no solution
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdAddToScc);

            // Activate the provider and test the result
            target.SetActive();
            Assert.AreEqual(true, target.Active, "Microsoft.Samples.VisualStudio.SourceControlIntegration.SccProvider.SccProviderService.Active was not reported correctly.");

            // The commands should be invisible when there is no solution
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdUseSccOffline);

            // Commands that don't belong to our package should not be supported
            result = _sccProvider.QueryStatus(ref guidCmdGroup, 1, cmdUnsupported, IntPtr.Zero);
            Assert.AreEqual((int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED, result);

            // Deactivate the provider and test the result
            target.SetInactive();
            Assert.AreEqual(false, target.Active, "Microsoft.Samples.VisualStudio.SourceControlIntegration.SccProvider.SccProviderService.Active was not reported correctly.");

            // Create a solution
            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());

            project.AddItem(Path.GetTempFileName());
            solution.AddProject(project);

            // The commands should be invisible when the provider is not active
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdUseSccOffline);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdViewToolWindow);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdToolWindowToolbarCommand);

            // Activate the provider and test the result
            target.SetActive();
            Assert.AreEqual(true, target.Active, "Microsoft.Samples.VisualStudio.SourceControlIntegration.SccProvider.SccProviderService.Active was not reported correctly.");

            // The command should be visible but disabled now, except the toolwindow ones
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdViewToolWindow);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdToolWindowToolbarCommand);

            // Set selection to solution node
            VSITEMSELECTION selSolutionRoot;

            selSolutionRoot.pHier         = _solution as IVsHierarchy;
            selSolutionRoot.itemid        = VSConstants.VSITEMID_ROOT;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot };

            // The add command should be available, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Still solution hierarchy, but other way
            selSolutionRoot.pHier         = null;
            selSolutionRoot.itemid        = VSConstants.VSITEMID_ROOT;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot };

            // The add command should be available, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Set selection to project node
            VSITEMSELECTION selProjectRoot;

            selProjectRoot.pHier          = project as IVsHierarchy;
            selProjectRoot.itemid         = VSConstants.VSITEMID_ROOT;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selProjectRoot };

            // The add command should be available, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Set selection to project item
            VSITEMSELECTION selProjectItem;

            selProjectItem.pHier          = project as IVsHierarchy;
            selProjectItem.itemid         = 0;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selProjectItem };

            // The add command should be available, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Set selection to project and item node and add project to scc
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selProjectRoot, selProjectItem };
            VerifyCommandExecution(cmdAddToScc);

            // The add command and checkin should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdUseSccOffline);

            // Checkout the project
            VerifyCommandExecution(cmdCheckout);

            // The add command and checkout should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdUseSccOffline);

            // Select the solution
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot };

            // The checkout and offline should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Checkin the project
            VerifyCommandExecution(cmdCheckin);

            // The add command and checkout should be enabled, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Add the solution to scc
            VerifyCommandExecution(cmdAddToScc);

            // The add command and checkin should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdUseSccOffline);

            // Select the solution and project
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot, selProjectRoot };

            // Take the project and solution offline
            VerifyCommandExecution(cmdUseSccOffline);

            // The offline command should be latched
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_LATCHED, cmdUseSccOffline);

            // Select the solution only
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot };

            // Take the solution online
            VerifyCommandExecution(cmdUseSccOffline);

            // The offline command should be normal again
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdUseSccOffline);

            // Select the solution and project
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot, selProjectRoot };

            // The offline command should be disabled for mixed selection
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Add a new item to the project
            project.AddItem(Path.GetTempFileName());

            // Select the new item
            selProjectItem.pHier          = project as IVsHierarchy;
            selProjectItem.itemid         = 1;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selProjectItem };

            // The add command and checkout should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_LATCHED, cmdUseSccOffline);

            // Checkin the new file (this should do an add)
            VerifyCommandExecution(cmdCheckin);

            // The add command and checkout should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_LATCHED, cmdUseSccOffline);
        }
        public void TestOpenCloseControlled()
        {
            const string strProviderName           = "Sample Source Control Provider:{B0BAC05D-2000-41D1-A6C3-704E6C1A3DE2}";
            const string strSolutionPersistanceKey = "SampleSourceControlProviderSolutionProperties";
            const string strSolutionUserOptionsKey = "SampleSourceControlProvider";

            int result = 0;

            // Create a solution
            SccProviderService target = GetSccProviderServiceInstance;

            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());

            solution.AddProject(project);

            // Check solution props
            VSQUERYSAVESLNPROPS[] saveSolnProps = new VSQUERYSAVESLNPROPS[1];
            result = sccProvider.QuerySaveSolutionProps(null, saveSolnProps);
            Assert.AreEqual(VSConstants.S_OK, result);
            Assert.AreEqual <VSQUERYSAVESLNPROPS>(VSQUERYSAVESLNPROPS.QSP_HasNoProps, saveSolnProps[0]);

            // Add the solution to source control.
            Hashtable uncontrolled = new Hashtable();

            uncontrolled[project as IVsSccProject2] = true;
            target.AddProjectsToSourceControl(ref uncontrolled, true);

            // Solution should be dirty now
            result = sccProvider.QuerySaveSolutionProps(null, saveSolnProps);
            Assert.AreEqual(VSConstants.S_OK, result);
            Assert.AreEqual <VSQUERYSAVESLNPROPS>(VSQUERYSAVESLNPROPS.QSP_HasDirtyProps, saveSolnProps[0]);

            // Set the project offline so we'll have something to save in the "suo" stream
            target.ToggleOfflineStatus(project);

            // Force the provider to write the solution info into a stream
            IStream pOptionsStream = new ComStreamFromDataStream(new MemoryStream()) as IStream;

            sccProvider.WriteUserOptions(pOptionsStream, strSolutionUserOptionsKey);
            // Move the stream position to the beginning
            LARGE_INTEGER liOffset;

            liOffset.QuadPart = 0;
            ULARGE_INTEGER[] ulPosition = new ULARGE_INTEGER[1];
            pOptionsStream.Seek(liOffset, 0, ulPosition);

            // Write solution props
            BaseMock propertyBag = MockPropertyBagProvider.GetWritePropertyBag();

            sccProvider.WriteSolutionProps(null, strSolutionPersistanceKey, propertyBag as IPropertyBag);

            // Close the solution to clean up the scc status
            int pfCancel = 0;

            target.OnQueryCloseProject(project, 0, ref pfCancel);
            target.OnQueryCloseSolution(null, ref pfCancel);
            Assert.AreEqual(pfCancel, 0, "Solution close was canceled");
            target.OnBeforeCloseProject(project, 0);
            // Theoretically the project should have called this, but especially after an add to scc, some projects forget to call it
            // target.UnregisterSccProject(project);
            target.OnBeforeCloseSolution(null);
            target.OnAfterCloseSolution(null);

            // Now attempt the "reopen"
            // The solution reads the solution properties
            propertyBag = MockPropertyBagProvider.GetReadPropertyBag();
            sccProvider.ReadSolutionProps(null, null, null, strSolutionPersistanceKey, 1, propertyBag as IPropertyBag);
            // The solution reads the user options from the stream where they were written before
            sccProvider.ReadUserOptions(pOptionsStream, strSolutionUserOptionsKey);
            // Then the projects are opened and register with the provider
            target.RegisterSccProject(project, "Project's location", "AuxPath", Path.GetDirectoryName(project.ProjectFile), strProviderName);
            // solution event fired for this project
            target.OnAfterOpenProject(project, 0);
            // Then solution completes opening
            target.OnAfterOpenSolution(null, 0);

            Assert.IsTrue(target.IsProjectControlled(null), "The solution's controlled status was not correctly persisted or read from property bag");
            Assert.IsTrue(target.IsProjectControlled(project), "The project's controlled status was not correctly set");
            Assert.IsTrue(target.IsProjectOffline(project), "The project's offline status was incorrectly persisted or read from suo stream");
        }
        public void TestTPDEvents()
        {
            int result = 0;

            SccProviderService target = GetSccProviderServiceInstance;

            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());

            solution.AddProject(project);

            Hashtable uncontrolled = new Hashtable();

            uncontrolled[project as IVsSccProject2] = true;
            target.AddProjectsToSourceControl(ref uncontrolled, true);
            // In real live, a QueryEdit call on the project file would be necessary to add/rename/delete items

            // Add a new item and fire the appropriate events
            string pendingAddFile = Path.GetTempFileName();

            VSQUERYADDFILERESULTS[] pSummaryResultAdd = new VSQUERYADDFILERESULTS[1];
            VSQUERYADDFILERESULTS[] rgResultsAdd      = new VSQUERYADDFILERESULTS[1];
            result = target.OnQueryAddFiles(project as IVsProject, 1, new string[] { pendingAddFile }, null, pSummaryResultAdd, rgResultsAdd);
            Assert.AreEqual <int>(VSConstants.E_NOTIMPL, result);
            project.AddItem(pendingAddFile);
            result = target.OnAfterAddFilesEx(1, 1, new IVsProject[] { project as IVsProject }, new int[] { 0 }, new string[] { pendingAddFile }, null);
            Assert.AreEqual <int>(VSConstants.E_NOTIMPL, result);
            Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(pendingAddFile), "Incorrect status returned");

            // Checkin the pending add file
            target.AddFileToSourceControl(pendingAddFile);

            // Rename the item and verify the file remains is controlled
            string newName = pendingAddFile + ".renamed";

            VSQUERYRENAMEFILERESULTS[] pSummaryResultRen = new VSQUERYRENAMEFILERESULTS[1];
            VSQUERYRENAMEFILERESULTS[] rgResultsRen      = new VSQUERYRENAMEFILERESULTS[1];
            result = target.OnQueryRenameFiles(project as IVsProject, 1, new string[] { pendingAddFile }, new string[] { newName }, null, pSummaryResultRen, rgResultsRen);
            Assert.AreEqual <int>(VSConstants.E_NOTIMPL, result);
            project.RenameItem(pendingAddFile, newName);
            result = target.OnAfterRenameFiles(1, 1, new IVsProject[] { project as IVsProject }, new int[] { 0 }, new string[] { pendingAddFile }, new string[] { newName }, new VSRENAMEFILEFLAGS[] { VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_NoFlags });
            Assert.AreEqual <int>(VSConstants.S_OK, result);
            Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(pendingAddFile), "Incorrect status returned");
            Assert.AreEqual(SourceControlStatus.scsCheckedIn, target.GetFileStatus(newName), "Incorrect status returned");

            // Mock the UIShell service to answer Cancel to the dialog invocation
            BaseMock mockUIShell = MockUiShellProvider.GetShowMessageBoxCancel();

            serviceProvider.AddService(typeof(IVsUIShell), mockUIShell, true);
            // Try to delete the file from project; the delete should not be allowed
            VSQUERYREMOVEFILERESULTS[] pSummaryResultDel = new VSQUERYREMOVEFILERESULTS[1];
            VSQUERYREMOVEFILERESULTS[] rgResultsDel      = new VSQUERYREMOVEFILERESULTS[1];
            result = target.OnQueryRemoveFiles(project as IVsProject, 1, new string[] { newName }, null, pSummaryResultDel, rgResultsDel);
            Assert.AreEqual <int>(VSConstants.S_OK, result);
            Assert.AreEqual <VSQUERYREMOVEFILERESULTS>(VSQUERYREMOVEFILERESULTS.VSQUERYREMOVEFILERESULTS_RemoveNotOK, pSummaryResultDel[0]);
            // Mock the UIShell service to answer Yes to the dialog invocation
            serviceProvider.RemoveService(typeof(IVsUIShell));
            mockUIShell = MockUiShellProvider.GetShowMessageBoxYes();
            serviceProvider.AddService(typeof(IVsUIShell), mockUIShell, true);
            // Try to delete the file from project; the delete should be allowed this time
            result = target.OnQueryRemoveFiles(project as IVsProject, 1, new string[] { newName }, null, pSummaryResultDel, rgResultsDel);
            Assert.AreEqual <int>(VSConstants.S_OK, result);
            Assert.AreEqual <VSQUERYREMOVEFILERESULTS>(VSQUERYREMOVEFILERESULTS.VSQUERYREMOVEFILERESULTS_RemoveOK, pSummaryResultDel[0]);
            // Remove the file from project
            project.RemoveItem(newName);
            result = target.OnAfterRemoveFiles(1, 1, new IVsProject[] { project as IVsProject }, new int[] { 0 }, new string[] { newName }, null);
            Assert.AreEqual <int>(VSConstants.E_NOTIMPL, result);
        }
        public void TestFileStatus()
        {
            SccProviderService target = GetSccProviderServiceInstance;

            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());

            project.AddItem(Path.GetTempFileName());
            solution.AddProject(project);

            VsStateIcon [] rgsiGlyphs           = new VsStateIcon[1];
            VsStateIcon [] rgsiGlyphsFromStatus = new VsStateIcon[1];
            uint[]         rgdwSccStatus        = new uint[1];
            int            result = 0;
            string         strTooltip;

            // Check glyphs and statuses for uncontrolled items
            IList <string> files = new string[] { solution.SolutionFile, project.ProjectFile, project.ProjectItems[0] };

            foreach (string file in files)
            {
                Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(file), "Incorrect status returned");

                result = target.GetSccGlyph(1, new string[] { file }, rgsiGlyphs, rgdwSccStatus);
                Assert.AreEqual <int>(VSConstants.S_OK, result);
                Assert.AreEqual <VsStateIcon>(VsStateIcon.STATEICON_BLANK, rgsiGlyphs[0]);
                Assert.AreEqual <uint>((uint)__SccStatus.SCC_STATUS_NOTCONTROLLED, rgdwSccStatus[0]);

                result = target.GetSccGlyphFromStatus(rgdwSccStatus[0], rgsiGlyphsFromStatus);
                Assert.AreEqual <int>(VSConstants.S_OK, result);
                Assert.AreEqual <VsStateIcon>(rgsiGlyphs[0], rgsiGlyphsFromStatus[0]);
            }

            // Uncontrolled items should not have tooltips
            target.GetGlyphTipText(project as IVsHierarchy, VSConstants.VSITEMID_ROOT, out strTooltip);
            Assert.IsTrue(strTooltip.Length == 0);

            Hashtable uncontrolled = new Hashtable();

            uncontrolled[project as IVsSccProject2] = true;
            target.AddProjectsToSourceControl(ref uncontrolled, true);

            foreach (string file in files)
            {
                Assert.AreEqual(SourceControlStatus.scsCheckedIn, target.GetFileStatus(file), "Incorrect status returned");

                result = target.GetSccGlyph(1, new string[] { file }, rgsiGlyphs, rgdwSccStatus);
                Assert.AreEqual <int>(VSConstants.S_OK, result);
                Assert.AreEqual <VsStateIcon>(VsStateIcon.STATEICON_CHECKEDIN, rgsiGlyphs[0]);
                Assert.AreEqual <uint>((uint)__SccStatus.SCC_STATUS_CONTROLLED, rgdwSccStatus[0]);

                result = target.GetSccGlyphFromStatus(rgdwSccStatus[0], rgsiGlyphsFromStatus);
                Assert.AreEqual <int>(VSConstants.S_OK, result);
                Assert.AreEqual <VsStateIcon>(rgsiGlyphs[0], rgsiGlyphsFromStatus[0]);
            }

            // Checked in items should have tooltips
            target.GetGlyphTipText(project as IVsHierarchy, VSConstants.VSITEMID_ROOT, out strTooltip);
            Assert.IsTrue(strTooltip.Length > 0);

            foreach (string file in files)
            {
                target.CheckoutFile(file);
                Assert.AreEqual(SourceControlStatus.scsCheckedOut, target.GetFileStatus(file), "Incorrect status returned");

                result = target.GetSccGlyph(1, new string[] { file }, rgsiGlyphs, rgdwSccStatus);
                Assert.AreEqual <int>(VSConstants.S_OK, result);
                Assert.AreEqual <VsStateIcon>(VsStateIcon.STATEICON_CHECKEDOUT, rgsiGlyphs[0]);
                Assert.AreEqual <uint>((uint)__SccStatus.SCC_STATUS_CHECKEDOUT, rgdwSccStatus[0]);

                result = target.GetSccGlyphFromStatus(rgdwSccStatus[0], rgsiGlyphsFromStatus);
                Assert.AreEqual <int>(VSConstants.S_OK, result);
                Assert.AreEqual <VsStateIcon>(rgsiGlyphs[0], rgsiGlyphsFromStatus[0]);
            }

            // Checked out items should have tooltips, too
            target.GetGlyphTipText(project as IVsHierarchy, VSConstants.VSITEMID_ROOT, out strTooltip);
            Assert.IsTrue(strTooltip.Length > 0);

            foreach (string file in files)
            {
                target.CheckinFile(file);
                Assert.AreEqual(SourceControlStatus.scsCheckedIn, target.GetFileStatus(file), "Incorrect status returned");

                result = target.GetSccGlyph(1, new string[] { file }, rgsiGlyphs, rgdwSccStatus);
                Assert.AreEqual <int>(VSConstants.S_OK, result);
                Assert.AreEqual <VsStateIcon>(VsStateIcon.STATEICON_CHECKEDIN, rgsiGlyphs[0]);
                Assert.AreEqual <uint>((uint)__SccStatus.SCC_STATUS_CONTROLLED, rgdwSccStatus[0]);
            }

            // Add a new file to the project (don't worry about TPD events for now)
            string pendingAddFile = Path.GetTempFileName();

            project.AddItem(pendingAddFile);
            Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(pendingAddFile), "Incorrect status returned");

            result = target.GetSccGlyph(1, new string[] { pendingAddFile }, rgsiGlyphs, rgdwSccStatus);
            Assert.AreEqual <int>(VSConstants.S_OK, result);
            Assert.AreEqual <VsStateIcon>(VsStateIcon.STATEICON_CHECKEDOUT, rgsiGlyphs[0]);
            Assert.AreEqual <uint>((uint)__SccStatus.SCC_STATUS_CHECKEDOUT, rgdwSccStatus[0]);

            // Pending add items should have tooltips, too
            target.GetGlyphTipText(project as IVsHierarchy, 1, out strTooltip);
            Assert.IsTrue(strTooltip.Length > 0);

            // Checkin the pending add file
            target.AddFileToSourceControl(pendingAddFile);
            Assert.AreEqual(SourceControlStatus.scsCheckedIn, target.GetFileStatus(pendingAddFile), "Incorrect status returned");

            result = target.GetSccGlyph(1, new string[] { pendingAddFile }, rgsiGlyphs, rgdwSccStatus);
            Assert.AreEqual <int>(VSConstants.S_OK, result);
            Assert.AreEqual <VsStateIcon>(VsStateIcon.STATEICON_CHECKEDIN, rgsiGlyphs[0]);
            Assert.AreEqual <uint>((uint)__SccStatus.SCC_STATUS_CONTROLLED, rgdwSccStatus[0]);
        }
        public void QueryEditQuerySaveTest()
        {
            uint pfEditVerdict;
            uint prgfMoreInfo;
            uint pdwQSResult;
            int  result;

            SccProviderService target = GetSccProviderServiceInstance;

            // check the functions that are not implemented
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.BeginQuerySaveBatch());
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.EndQuerySaveBatch());
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.DeclareReloadableFile("", 0, null));
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.DeclareUnreloadableFile("", 0, null));
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.OnAfterSaveUnreloadableFile("", 0, null));
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.IsReloadable("", out result));
            Assert.AreEqual(1, result, "Not the right return value from IsReloadable");

            // Create a basic service provider

            IVsShell shell = MockShellProvider.GetShellForCommandLine() as IVsShell;

            serviceProvider.AddService(typeof(IVsShell), shell, true);

            // Command line tests
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_ReportOnly, 1, new string[] { "Dummy.txt" }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)0, prgfMoreInfo, "QueryEdit failed.");

            result = target.QuerySaveFile("Dummy.txt", 0, null, out pdwQSResult);
            Assert.AreEqual(VSConstants.S_OK, result, "QuerySave failed.");
            Assert.AreEqual((uint)tagVSQuerySaveResult.QSR_SaveOK, pdwQSResult, "QueryEdit failed.");

            serviceProvider.RemoveService(typeof(SVsShell));

            // UI mode tests
            shell = MockShellProvider.GetShellForUI() as IVsShell;
            serviceProvider.AddService(typeof(SVsShell), shell, true);

            // Edit of an uncontrolled file that doesn't exist on disk
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_ReportOnly, 1, new string[] { "Dummy.txt" }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)0, prgfMoreInfo, "QueryEdit failed.");

            // Mock a solution with a project and a file
            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());

            solution.AddProject(project);
            // Add only the project to source control.
            Hashtable uncontrolled = new Hashtable();

            uncontrolled[project as IVsSccProject2] = true;
            target.AddProjectsToSourceControl(ref uncontrolled, false);
            // Check that solution file is not controlled
            Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(solution.SolutionFile), "Incorrect status returned");
            // Make the solution read-only on disk
            File.SetAttributes(solution.SolutionFile, FileAttributes.ReadOnly);

            // QueryEdit in report mode for uncontrolled readonly file
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_ReportOnly, 1, new string[] { solution.SolutionFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditNotOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)(tagVSQueryEditResultFlags.QER_EditNotPossible | tagVSQueryEditResultFlags.QER_ReadOnlyNotUnderScc), prgfMoreInfo, "QueryEdit failed.");

            // QueryEdit in silent mode for uncontrolled readonly file
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_SilentMode, 1, new string[] { solution.SolutionFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditNotOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)(tagVSQueryEditResultFlags.QER_NoisyPromptRequired), (uint)(tagVSQueryEditResultFlags.QER_NoisyPromptRequired) & prgfMoreInfo, "QueryEdit failed.");

            // Mock the UIShell service to answer Yes to the dialog invocation
            BaseMock mockUIShell = MockUiShellProvider.GetShowMessageBoxYes();

            serviceProvider.AddService(typeof(IVsUIShell), mockUIShell, true);

            // QueryEdit for uncontrolled readonly file: allow the edit and make the file read-write
            result = target.QueryEditFiles(0, 1, new string[] { solution.SolutionFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)0, prgfMoreInfo, "QueryEdit failed.");
            Assert.AreEqual <FileAttributes>(FileAttributes.Normal, File.GetAttributes(solution.SolutionFile), "File was not made writable");
            serviceProvider.RemoveService(typeof(IVsUIShell));

            // QueryEdit in report mode for controlled readonly file
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_ReportOnly, 1, new string[] { project.ProjectFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditNotOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)(tagVSQueryEditResultFlags.QER_EditNotPossible | tagVSQueryEditResultFlags.QER_ReadOnlyUnderScc), prgfMoreInfo, "QueryEdit failed.");

            // QueryEdit in silent mode for controlled readonly file: should allow the edit and make the file read-write
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_SilentMode, 1, new string[] { project.ProjectFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResultFlags.QER_MaybeCheckedout, prgfMoreInfo, "QueryEdit failed.");
            Assert.AreEqual <FileAttributes>(FileAttributes.Normal, File.GetAttributes(solution.SolutionFile), "File was not made writable");
            serviceProvider.RemoveService(typeof(IVsUIShell));
        }
        public void TestTPDEvents()
        {
            int result = 0;

            SccProviderService target = GetSccProviderServiceInstance;
            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());
            solution.AddProject(project);

            Hashtable uncontrolled = new Hashtable();
            uncontrolled[project as IVsSccProject2] = true;
            target.AddProjectsToSourceControl(ref uncontrolled, true);
            // In real live, a QueryEdit call on the project file would be necessary to add/rename/delete items

            // Add a new item and fire the appropriate events
            string pendingAddFile = Path.GetTempFileName();
            VSQUERYADDFILERESULTS[] pSummaryResultAdd = new VSQUERYADDFILERESULTS[1];
            VSQUERYADDFILERESULTS[] rgResultsAdd = new VSQUERYADDFILERESULTS[1];
            result = target.OnQueryAddFiles(project as IVsProject, 1, new string[] {pendingAddFile},  null, pSummaryResultAdd, rgResultsAdd);
            Assert.AreEqual<int>(VSConstants.E_NOTIMPL, result);
            project.AddItem(pendingAddFile);
            result = target.OnAfterAddFilesEx(1, 1, new IVsProject[] { project as IVsProject }, new int[] { 0 }, new string[] { pendingAddFile }, null);
            Assert.AreEqual<int>(VSConstants.E_NOTIMPL, result);
            Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(pendingAddFile), "Incorrect status returned");

            // Checkin the pending add file
            target.AddFileToSourceControl(pendingAddFile);

            // Rename the item and verify the file remains is controlled
            string newName = pendingAddFile + ".renamed";
            VSQUERYRENAMEFILERESULTS[] pSummaryResultRen = new VSQUERYRENAMEFILERESULTS[1];
            VSQUERYRENAMEFILERESULTS[] rgResultsRen = new VSQUERYRENAMEFILERESULTS[1];
            result = target.OnQueryRenameFiles(project as IVsProject, 1, new string[] { pendingAddFile }, new string[] { newName }, null, pSummaryResultRen, rgResultsRen);
            Assert.AreEqual<int>(VSConstants.E_NOTIMPL, result);
            project.RenameItem(pendingAddFile, newName);
            result = target.OnAfterRenameFiles(1, 1, new IVsProject[] {project as IVsProject}, new int[] {0}, new string[] { pendingAddFile }, new string[] { newName }, new VSRENAMEFILEFLAGS[] {VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_NoFlags});
            Assert.AreEqual<int>(VSConstants.S_OK, result);
            Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(pendingAddFile), "Incorrect status returned");
            Assert.AreEqual(SourceControlStatus.scsCheckedIn, target.GetFileStatus(newName), "Incorrect status returned");

            // Mock the UIShell service to answer Cancel to the dialog invocation
            BaseMock mockUIShell = MockUiShellProvider.GetShowMessageBoxCancel();
            serviceProvider.AddService(typeof(IVsUIShell), mockUIShell, true);
            // Try to delete the file from project; the delete should not be allowed
            VSQUERYREMOVEFILERESULTS[] pSummaryResultDel = new VSQUERYREMOVEFILERESULTS[1];
            VSQUERYREMOVEFILERESULTS[] rgResultsDel = new VSQUERYREMOVEFILERESULTS[1];
            result = target.OnQueryRemoveFiles(project as IVsProject, 1, new string[] { newName }, null, pSummaryResultDel, rgResultsDel);
            Assert.AreEqual<int>(VSConstants.S_OK, result);
            Assert.AreEqual<VSQUERYREMOVEFILERESULTS>(VSQUERYREMOVEFILERESULTS.VSQUERYREMOVEFILERESULTS_RemoveNotOK, pSummaryResultDel[0]);
            // Mock the UIShell service to answer Yes to the dialog invocation
            serviceProvider.RemoveService(typeof(IVsUIShell));
            mockUIShell = MockUiShellProvider.GetShowMessageBoxYes();
            serviceProvider.AddService(typeof(IVsUIShell), mockUIShell, true);
            // Try to delete the file from project; the delete should be allowed this time
            result = target.OnQueryRemoveFiles(project as IVsProject, 1, new string[] { newName }, null, pSummaryResultDel, rgResultsDel);
            Assert.AreEqual<int>(VSConstants.S_OK, result);
            Assert.AreEqual<VSQUERYREMOVEFILERESULTS>(VSQUERYREMOVEFILERESULTS.VSQUERYREMOVEFILERESULTS_RemoveOK, pSummaryResultDel[0]);
            // Remove the file from project
            project.RemoveItem(newName);
            result = target.OnAfterRemoveFiles(1, 1, new IVsProject[] { project as IVsProject }, new int[] { 0 }, new string[] { newName }, null);
            Assert.AreEqual<int>(VSConstants.E_NOTIMPL, result);
        }
        public void TestSccMenuCommands()
        {
            int result = 0;
            Guid badGuid = new Guid();
            Guid guidCmdGroup = GuidList.guidSccProviderCmdSet;

            OLECMD[] cmdAddToScc = new OLECMD[1];
            cmdAddToScc[0].cmdID = CommandId.icmdAddToSourceControl;
            OLECMD[] cmdCheckin = new OLECMD[1];
            cmdCheckin[0].cmdID = CommandId.icmdCheckin;
            OLECMD[] cmdCheckout = new OLECMD[1];
            cmdCheckout[0].cmdID = CommandId.icmdCheckout;
            OLECMD[] cmdUseSccOffline = new OLECMD[1];
            cmdUseSccOffline[0].cmdID = CommandId.icmdUseSccOffline;
            OLECMD[] cmdViewToolWindow = new OLECMD[1];
            cmdViewToolWindow[0].cmdID = CommandId.icmdViewToolWindow;
            OLECMD[] cmdToolWindowToolbarCommand = new OLECMD[1];
            cmdToolWindowToolbarCommand[0].cmdID = CommandId.icmdToolWindowToolbarCommand;
            OLECMD[] cmdUnsupported = new OLECMD[1];
            cmdUnsupported[0].cmdID = 0;

            // Initialize the provider, etc
            SccProviderService target = GetSccProviderServiceInstance;

            // Mock a service implementing IVsMonitorSelection
            BaseMock monitorSelection = MockIVsMonitorSelectionFactory.GetMonSel();
            serviceProvider.AddService(typeof(IVsMonitorSelection), monitorSelection, true);

            // Commands that don't belong to our package should not be supported
            result = _sccProvider.QueryStatus(ref badGuid, 1, cmdAddToScc, IntPtr.Zero);
            Assert.AreEqual((int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED, result);

            // The command should be invisible when there is no solution
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdAddToScc);

            // Activate the provider and test the result
            target.SetActive();
            Assert.AreEqual(true, target.Active, "Microsoft.Samples.VisualStudio.SourceControlIntegration.SccProvider.SccProviderService.Active was not reported correctly.");

            // The commands should be invisible when there is no solution
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdUseSccOffline);

            // Commands that don't belong to our package should not be supported
            result = _sccProvider.QueryStatus(ref guidCmdGroup, 1, cmdUnsupported, IntPtr.Zero);
            Assert.AreEqual((int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED, result);

            // Deactivate the provider and test the result
            target.SetInactive();
            Assert.AreEqual(false, target.Active, "Microsoft.Samples.VisualStudio.SourceControlIntegration.SccProvider.SccProviderService.Active was not reported correctly.");

            // Create a solution
            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());
            project.AddItem(Path.GetTempFileName());
            solution.AddProject(project);

            // The commands should be invisible when the provider is not active
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdUseSccOffline);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdViewToolWindow);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_INVISIBLE, cmdToolWindowToolbarCommand);

            // Activate the provider and test the result
            target.SetActive();
            Assert.AreEqual(true, target.Active, "Microsoft.Samples.VisualStudio.SourceControlIntegration.SccProvider.SccProviderService.Active was not reported correctly.");

            // The command should be visible but disabled now, except the toolwindow ones
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdViewToolWindow);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdToolWindowToolbarCommand);

            // Set selection to solution node
            VSITEMSELECTION selSolutionRoot;
            selSolutionRoot.pHier = _solution as IVsHierarchy;
            selSolutionRoot.itemid = VSConstants.VSITEMID_ROOT;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot };

            // The add command should be available, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Still solution hierarchy, but other way
            selSolutionRoot.pHier = null;
            selSolutionRoot.itemid = VSConstants.VSITEMID_ROOT;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot };

            // The add command should be available, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Set selection to project node
            VSITEMSELECTION selProjectRoot;
            selProjectRoot.pHier = project as IVsHierarchy;
            selProjectRoot.itemid = VSConstants.VSITEMID_ROOT;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selProjectRoot };

            // The add command should be available, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Set selection to project item
            VSITEMSELECTION selProjectItem;
            selProjectItem.pHier = project as IVsHierarchy;
            selProjectItem.itemid = 0;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selProjectItem };

            // The add command should be available, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Set selection to project and item node and add project to scc
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selProjectRoot, selProjectItem };
            VerifyCommandExecution(cmdAddToScc);

            // The add command and checkin should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdUseSccOffline);

            // Checkout the project
            VerifyCommandExecution(cmdCheckout);

            // The add command and checkout should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdUseSccOffline);

            // Select the solution
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot };

            // The checkout and offline should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Checkin the project
            VerifyCommandExecution(cmdCheckin);

            // The add command and checkout should be enabled, rest should be disabled
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Add the solution to scc
            VerifyCommandExecution(cmdAddToScc);

            // The add command and checkin should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdUseSccOffline);

            // Select the solution and project
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot, selProjectRoot };

            // Take the project and solution offline
            VerifyCommandExecution(cmdUseSccOffline);

            // The offline command should be latched
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_LATCHED, cmdUseSccOffline);

            // Select the solution only
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot};

            // Take the solution online
            VerifyCommandExecution(cmdUseSccOffline);

            // The offline command should be normal again
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdUseSccOffline);

            // Select the solution and project
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selSolutionRoot, selProjectRoot };

            // The offline command should be disabled for mixed selection
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdUseSccOffline);

            // Add a new item to the project
            project.AddItem(Path.GetTempFileName());

            // Select the new item
            selProjectItem.pHier = project as IVsHierarchy;
            selProjectItem.itemid = 1;
            monitorSelection["Selection"] = new VSITEMSELECTION[] { selProjectItem };

            // The add command and checkout should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_LATCHED, cmdUseSccOffline);

            // Checkin the new file (this should do an add)
            VerifyCommandExecution(cmdCheckin);

            // The add command and checkout should be disabled, rest should be available now
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdAddToScc);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED, cmdCheckin);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED, cmdCheckout);
            VerifyCommandStatus(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_LATCHED, cmdUseSccOffline);
        }
        public void TestOpenCloseControlled()
        {
            const string strProviderName = "Sample Source Control Provider:{B0BAC05D-2000-41D1-A6C3-704E6C1A3DE2}";
            const string strSolutionPersistanceKey = "SampleSourceControlProviderSolutionProperties";
            const string strSolutionUserOptionsKey = "SampleSourceControlProvider";

            int result = 0;

            // Create a solution
            SccProviderService target = GetSccProviderServiceInstance;
            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());
            solution.AddProject(project);

            // Check solution props
            VSQUERYSAVESLNPROPS[] saveSolnProps = new VSQUERYSAVESLNPROPS[1];
            result = sccProvider.QuerySaveSolutionProps(null, saveSolnProps);
            Assert.AreEqual(VSConstants.S_OK, result);
            Assert.AreEqual<VSQUERYSAVESLNPROPS>(VSQUERYSAVESLNPROPS.QSP_HasNoProps, saveSolnProps[0]);

            // Add the solution to source control.
            Hashtable uncontrolled = new Hashtable();
            uncontrolled[project as IVsSccProject2] = true;
            target.AddProjectsToSourceControl(ref uncontrolled, true);

            // Solution should be dirty now
            result = sccProvider.QuerySaveSolutionProps(null, saveSolnProps);
            Assert.AreEqual(VSConstants.S_OK, result);
            Assert.AreEqual<VSQUERYSAVESLNPROPS>(VSQUERYSAVESLNPROPS.QSP_HasDirtyProps, saveSolnProps[0]);

            // Set the project offline so we'll have something to save in the "suo" stream
            target.ToggleOfflineStatus(project);

            // Force the provider to write the solution info into a stream
            IStream pOptionsStream = new ComStreamFromDataStream(new MemoryStream()) as IStream;
            sccProvider.WriteUserOptions(pOptionsStream, strSolutionUserOptionsKey);
            // Move the stream position to the beginning
            LARGE_INTEGER liOffset;
            liOffset.QuadPart = 0;
            ULARGE_INTEGER[] ulPosition = new ULARGE_INTEGER[1];
            pOptionsStream.Seek(liOffset, 0, ulPosition);

            // Write solution props
            BaseMock propertyBag = MockPropertyBagProvider.GetWritePropertyBag();
            sccProvider.WriteSolutionProps(null, strSolutionPersistanceKey, propertyBag as IPropertyBag);

            // Close the solution to clean up the scc status
            int pfCancel = 0;
            target.OnQueryCloseProject(project, 0, ref pfCancel);
            target.OnQueryCloseSolution(null, ref pfCancel);
            Assert.AreEqual(pfCancel, 0, "Solution close was canceled");
            target.OnBeforeCloseProject(project, 0);
            // Theoretically the project should have called this, but especially after an add to scc, some projects forget to call it
            // target.UnregisterSccProject(project);
            target.OnBeforeCloseSolution(null);
            target.OnAfterCloseSolution(null);

            // Now attempt the "reopen"
            // The solution reads the solution properties
            propertyBag = MockPropertyBagProvider.GetReadPropertyBag();
            sccProvider.ReadSolutionProps(null, null, null, strSolutionPersistanceKey, 1, propertyBag as IPropertyBag);
            // The solution reads the user options from the stream where they were written before
            sccProvider.ReadUserOptions(pOptionsStream, strSolutionUserOptionsKey);
            // Then the projects are opened and register with the provider
            target.RegisterSccProject(project, "Project's location", "AuxPath", Path.GetDirectoryName(project.ProjectFile), strProviderName);
            // solution event fired for this project
            target.OnAfterOpenProject(project, 0);
            // Then solution completes opening
            target.OnAfterOpenSolution(null, 0);

            Assert.IsTrue(target.IsProjectControlled(null), "The solution's controlled status was not correctly persisted or read from property bag");
            Assert.IsTrue(target.IsProjectControlled(project), "The project's controlled status was not correctly set");
            Assert.IsTrue(target.IsProjectOffline(project), "The project's offline status was incorrectly persisted or read from suo stream");
        }
        public void TestFileStatus()
        {
            SccProviderService target = GetSccProviderServiceInstance;
            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());
            project.AddItem(Path.GetTempFileName());
            solution.AddProject(project);

            VsStateIcon [] rgsiGlyphs = new VsStateIcon[1];
            VsStateIcon [] rgsiGlyphsFromStatus = new VsStateIcon[1];
            uint[] rgdwSccStatus = new uint[1];
            int result = 0;
            string strTooltip;

            // Check glyphs and statuses for uncontrolled items
            IList<string> files = new string[] { solution.SolutionFile, project.ProjectFile, project.ProjectItems[0] };
            foreach (string file in files)
            {
                Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(file), "Incorrect status returned");

                result = target.GetSccGlyph(1, new string[] { file }, rgsiGlyphs, rgdwSccStatus);
                Assert.AreEqual<int>(VSConstants.S_OK, result);
                Assert.AreEqual<VsStateIcon>(VsStateIcon.STATEICON_BLANK, rgsiGlyphs[0]);
                Assert.AreEqual<uint>((uint) __SccStatus.SCC_STATUS_NOTCONTROLLED, rgdwSccStatus[0]);

                result = target.GetSccGlyphFromStatus(rgdwSccStatus[0], rgsiGlyphsFromStatus);
                Assert.AreEqual<int>(VSConstants.S_OK, result);
                Assert.AreEqual<VsStateIcon>(rgsiGlyphs[0], rgsiGlyphsFromStatus[0]);
            }

            // Uncontrolled items should not have tooltips
            target.GetGlyphTipText(project as IVsHierarchy, VSConstants.VSITEMID_ROOT, out strTooltip);
            Assert.IsTrue(strTooltip.Length == 0);

            Hashtable uncontrolled = new Hashtable();
            uncontrolled[project as IVsSccProject2] = true;
            target.AddProjectsToSourceControl(ref uncontrolled, true);

            foreach (string file in files)
            {
                Assert.AreEqual(SourceControlStatus.scsCheckedIn, target.GetFileStatus(file), "Incorrect status returned");

                result = target.GetSccGlyph(1, new string[] { file }, rgsiGlyphs, rgdwSccStatus);
                Assert.AreEqual<int>(VSConstants.S_OK, result);
                Assert.AreEqual<VsStateIcon>(VsStateIcon.STATEICON_CHECKEDIN, rgsiGlyphs[0]);
                Assert.AreEqual<uint>((uint) __SccStatus.SCC_STATUS_CONTROLLED, rgdwSccStatus[0]);

                result = target.GetSccGlyphFromStatus(rgdwSccStatus[0], rgsiGlyphsFromStatus);
                Assert.AreEqual<int>(VSConstants.S_OK, result);
                Assert.AreEqual<VsStateIcon>(rgsiGlyphs[0], rgsiGlyphsFromStatus[0]);
            }

            // Checked in items should have tooltips
            target.GetGlyphTipText(project as IVsHierarchy, VSConstants.VSITEMID_ROOT, out strTooltip);
            Assert.IsTrue(strTooltip.Length > 0);

            foreach (string file in files)
            {
                target.CheckoutFile(file);
                Assert.AreEqual(SourceControlStatus.scsCheckedOut, target.GetFileStatus(file), "Incorrect status returned");

                result = target.GetSccGlyph(1, new string[] { file }, rgsiGlyphs, rgdwSccStatus);
                Assert.AreEqual<int>(VSConstants.S_OK, result);
                Assert.AreEqual<VsStateIcon>(VsStateIcon.STATEICON_CHECKEDOUT, rgsiGlyphs[0]);
                Assert.AreEqual<uint>((uint) __SccStatus.SCC_STATUS_CHECKEDOUT, rgdwSccStatus[0]);

                result = target.GetSccGlyphFromStatus(rgdwSccStatus[0], rgsiGlyphsFromStatus);
                Assert.AreEqual<int>(VSConstants.S_OK, result);
                Assert.AreEqual<VsStateIcon>(rgsiGlyphs[0], rgsiGlyphsFromStatus[0]);
            }

            // Checked out items should have tooltips, too
            target.GetGlyphTipText(project as IVsHierarchy, VSConstants.VSITEMID_ROOT, out strTooltip);
            Assert.IsTrue(strTooltip.Length > 0);

            foreach (string file in files)
            {
                target.CheckinFile(file);
                Assert.AreEqual(SourceControlStatus.scsCheckedIn, target.GetFileStatus(file), "Incorrect status returned");

                result = target.GetSccGlyph(1, new string[] { file }, rgsiGlyphs, rgdwSccStatus);
                Assert.AreEqual<int>(VSConstants.S_OK, result);
                Assert.AreEqual<VsStateIcon>(VsStateIcon.STATEICON_CHECKEDIN, rgsiGlyphs[0]);
                Assert.AreEqual<uint>((uint) __SccStatus.SCC_STATUS_CONTROLLED, rgdwSccStatus[0]);
            }

            // Add a new file to the project (don't worry about TPD events for now)
            string pendingAddFile = Path.GetTempFileName();
            project.AddItem(pendingAddFile);
            Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(pendingAddFile), "Incorrect status returned");

            result = target.GetSccGlyph(1, new string[] { pendingAddFile }, rgsiGlyphs, rgdwSccStatus);
            Assert.AreEqual<int>(VSConstants.S_OK, result);
            Assert.AreEqual<VsStateIcon>(VsStateIcon.STATEICON_CHECKEDOUT, rgsiGlyphs[0]);
            Assert.AreEqual<uint>((uint) __SccStatus.SCC_STATUS_CHECKEDOUT, rgdwSccStatus[0]);

            // Pending add items should have tooltips, too
            target.GetGlyphTipText(project as IVsHierarchy, 1, out strTooltip);
            Assert.IsTrue(strTooltip.Length > 0);

            // Checkin the pending add file
            target.AddFileToSourceControl(pendingAddFile);
            Assert.AreEqual(SourceControlStatus.scsCheckedIn, target.GetFileStatus(pendingAddFile), "Incorrect status returned");

            result = target.GetSccGlyph(1, new string[] { pendingAddFile }, rgsiGlyphs, rgdwSccStatus);
            Assert.AreEqual<int>(VSConstants.S_OK, result);
            Assert.AreEqual<VsStateIcon>(VsStateIcon.STATEICON_CHECKEDIN, rgsiGlyphs[0]);
            Assert.AreEqual<uint>((uint) __SccStatus.SCC_STATUS_CONTROLLED, rgdwSccStatus[0]);
        }
        public void QueryEditQuerySaveTest()
        {
            uint pfEditVerdict;
            uint prgfMoreInfo;
            uint pdwQSResult;
            int result;

            SccProviderService target = GetSccProviderServiceInstance;

            // check the functions that are not implemented
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.BeginQuerySaveBatch());
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.EndQuerySaveBatch());
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.DeclareReloadableFile("", 0, null));
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.DeclareUnreloadableFile("", 0, null));
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.OnAfterSaveUnreloadableFile("", 0, null));
            Assert.AreEqual((int)VSConstants.S_OK, (int)target.IsReloadable("", out result));
            Assert.AreEqual(1, result, "Not the right return value from IsReloadable");

            // Create a basic service provider

            IVsShell shell = MockShellProvider.GetShellForCommandLine() as IVsShell;
            serviceProvider.AddService(typeof(IVsShell), shell, true);

            // Command line tests
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_ReportOnly, 1, new string[] { "Dummy.txt" }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)0, prgfMoreInfo, "QueryEdit failed.");

            result = target.QuerySaveFile("Dummy.txt", 0, null, out pdwQSResult);
            Assert.AreEqual(VSConstants.S_OK, result, "QuerySave failed.");
            Assert.AreEqual((uint)tagVSQuerySaveResult.QSR_SaveOK, pdwQSResult, "QueryEdit failed.");

            serviceProvider.RemoveService(typeof(SVsShell));

            // UI mode tests
            shell = MockShellProvider.GetShellForUI() as IVsShell;
            serviceProvider.AddService(typeof(SVsShell), shell, true);

            // Edit of an uncontrolled file that doesn't exist on disk
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_ReportOnly, 1, new string[] { "Dummy.txt" }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)0, prgfMoreInfo, "QueryEdit failed.");

            // Mock a solution with a project and a file
            solution.SolutionFile = Path.GetTempFileName();
            MockIVsProject project = new MockIVsProject(Path.GetTempFileName());
            solution.AddProject(project);
            // Add only the project to source control.
            Hashtable uncontrolled = new Hashtable();
            uncontrolled[project as IVsSccProject2] = true;
            target.AddProjectsToSourceControl(ref uncontrolled, false);
            // Check that solution file is not controlled
            Assert.AreEqual(SourceControlStatus.scsUncontrolled, target.GetFileStatus(solution.SolutionFile), "Incorrect status returned");
            // Make the solution read-only on disk
            File.SetAttributes(solution.SolutionFile, FileAttributes.ReadOnly);

            // QueryEdit in report mode for uncontrolled readonly file
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_ReportOnly, 1, new string[] { solution.SolutionFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditNotOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)(tagVSQueryEditResultFlags.QER_EditNotPossible | tagVSQueryEditResultFlags.QER_ReadOnlyNotUnderScc), prgfMoreInfo, "QueryEdit failed.");

            // QueryEdit in silent mode for uncontrolled readonly file
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_SilentMode, 1, new string[] { solution.SolutionFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditNotOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)(tagVSQueryEditResultFlags.QER_NoisyPromptRequired), (uint)(tagVSQueryEditResultFlags.QER_NoisyPromptRequired) & prgfMoreInfo, "QueryEdit failed.");

            // Mock the UIShell service to answer Yes to the dialog invocation
            BaseMock mockUIShell = MockUiShellProvider.GetShowMessageBoxYes();
            serviceProvider.AddService(typeof(IVsUIShell), mockUIShell, true);

            // QueryEdit for uncontrolled readonly file: allow the edit and make the file read-write
            result = target.QueryEditFiles(0, 1, new string[] { solution.SolutionFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)0, prgfMoreInfo, "QueryEdit failed.");
            Assert.AreEqual<FileAttributes>(FileAttributes.Normal, File.GetAttributes(solution.SolutionFile), "File was not made writable");
            serviceProvider.RemoveService(typeof(IVsUIShell));

            // QueryEdit in report mode for controlled readonly file
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_ReportOnly, 1, new string[] { project.ProjectFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditNotOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)(tagVSQueryEditResultFlags.QER_EditNotPossible | tagVSQueryEditResultFlags.QER_ReadOnlyUnderScc), prgfMoreInfo, "QueryEdit failed.");

            // QueryEdit in silent mode for controlled readonly file: should allow the edit and make the file read-write
            result = target.QueryEditFiles((uint)tagVSQueryEditFlags.QEF_SilentMode, 1, new string[] { project.ProjectFile }, null, null, out pfEditVerdict, out prgfMoreInfo);
            Assert.AreEqual(VSConstants.S_OK, result, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResult.QER_EditOK, pfEditVerdict, "QueryEdit failed.");
            Assert.AreEqual((uint)tagVSQueryEditResultFlags.QER_MaybeCheckedout, prgfMoreInfo, "QueryEdit failed.");
            Assert.AreEqual<FileAttributes>(FileAttributes.Normal, File.GetAttributes(solution.SolutionFile), "File was not made writable");
            serviceProvider.RemoveService(typeof(IVsUIShell));
        }