public bool VerifyContentsMatch(
            string leftQueryCondition,
            string rightQueryCondition,
            HashSet <string> leftFieldNamesToIgnore,
            HashSet <string> rightFieldNamesToIgnore)
        {
            if (leftFieldNamesToIgnore == null)
            {
                leftFieldNamesToIgnore = new HashSet <string>();
            }
            if (rightFieldNamesToIgnore == null)
            {
                rightFieldNamesToIgnore = new HashSet <string>();
            }
            m_diffResult = new WitDiffResult();

            Stopwatch stopWatch = Stopwatch.StartNew();

            try
            {
                foreach (var filterPair in m_serverDiffEngine.Session.Filters.FilterPair)
                {
                    try
                    {
                        string sourceFilterString = GetSourceFilterString(filterPair);
                        string targetFilterString = GetTargetFilterString(filterPair);

                        bool compareFromLeftToRight = false;
                        bool compareFromRightToLeft = false;

                        if (string.IsNullOrEmpty(rightQueryCondition))
                        {
                            // No right rightQueryCondition was specified; perform left to right whether
                            // left is specified or not
                            compareFromLeftToRight = true;
                        }
                        else
                        {
                            // RightQueryCondition was specified so perform right to left
                            compareFromRightToLeft = true;
                            if (!string.IsNullOrEmpty(leftQueryCondition))
                            {
                                // LeftQueryCondition was also specified so perform both
                                compareFromLeftToRight = true;
                            }
                        }

                        if (compareFromLeftToRight)
                        {
                            CompareWorkItemsFromOneSideToTheOther(
                                sourceFilterString,
                                m_serverDiffEngine.Session.LeftMigrationSourceUniqueId,
                                m_serverDiffEngine.LeftMigrationSource,
                                m_serverDiffEngine.RightMigrationSource,
                                SourceWITDiffProvider,
                                TargetWITDiffProvider,
                                leftQueryCondition,
                                leftFieldNamesToIgnore,
                                rightFieldNamesToIgnore);
                        }

                        if (compareFromRightToLeft)
                        {
                            CompareWorkItemsFromOneSideToTheOther(
                                targetFilterString,
                                m_serverDiffEngine.Session.RightMigrationSourceUniqueId,
                                m_serverDiffEngine.RightMigrationSource,
                                m_serverDiffEngine.LeftMigrationSource,
                                TargetWITDiffProvider,
                                SourceWITDiffProvider,
                                rightQueryCondition,
                                rightFieldNamesToIgnore,
                                leftFieldNamesToIgnore);
                        }
                    }
                    finally
                    {
                        SourceWITDiffProvider.Cleanup();
                    }
                }
            }
            catch (Exception e)
            {
                m_diffResult.ProcessingErrors.Add(e.ToString());
                throw;
            }
            finally
            {
                stopWatch.Stop();
                m_serverDiffEngine.LogInfo(String.Format(CultureInfo.InvariantCulture, ServerDiffResources.WITServerDiffTimeToRun,
                                                         stopWatch.Elapsed.TotalSeconds));
            }

            if (!m_diffResult.AllContentsMatch)
            {
                m_diffResult.LogDifferenceReport(m_serverDiffEngine);
            }

            return(m_diffResult.AllContentsMatch);
        }
        public void LogDifferenceReport(ServerDiffEngine diffEngine)
        {
            diffEngine.LogInfo(MigrationToolkitResources.WitDiffResultReportSeparator);
            diffEngine.LogInfo(MigrationToolkitResources.WitDiffResultReportHeader);

            if (m_witDiffPairs.Count > 0)
            {
                foreach (WitDiffPair diffPair in m_witDiffPairs)
                {
                    string side1WorkItemId = diffPair.Side1DiffItem == null ? string.Empty : diffPair.Side1DiffItem.WorkItemId;
                    string side2WorkItemId = diffPair.Side2DiffItem == null ? string.Empty : diffPair.Side2DiffItem.WorkItemId;
                    diffEngine.LogError(String.Format(CultureInfo.InvariantCulture, MigrationToolkitResources.WitDiffResultWorkItemMismatch,
                                                      side1WorkItemId, diffPair.Side1Name, side2WorkItemId, diffPair.Side2Name,
                                                      diffPair.DiffType.ToString()));

                    if (diffPair.MissingFields.Count > 0)
                    {
                        diffEngine.LogError(MigrationToolkitResources.WitDiffResultWorkItemFieldMissingHeader);
                        foreach (WitDiffMissingField missingField in diffPair.MissingFields)
                        {
                            diffEngine.LogError(String.Format(CultureInfo.InvariantCulture, MigrationToolkitResources.WitDiffResultWorkItemFieldMissing,
                                                              missingField.FieldName, missingField.SourceName));
                        }
                    }

                    if (diffPair.DiffFields.Count > 0)
                    {
                        diffEngine.LogError(MigrationToolkitResources.WitDiffResultWorkItemFieldDiffHeader);
                        foreach (WitDiffField diffField in diffPair.DiffFields)
                        {
                            diffEngine.LogError(String.Format(CultureInfo.InvariantCulture, MigrationToolkitResources.WitDiffResultWorkItemFieldDiffDetail,
                                                              diffField.FieldName, diffField.SourceValue, diffField.TargetValue));
                        }
                    }

                    if (diffPair.MissingAttachments.Count > 0)
                    {
                        diffEngine.LogError(MigrationToolkitResources.WitDiffResultWorkItemAttachmentMissingHeader);
                        foreach (string missingAttachment in diffPair.MissingAttachments)
                        {
                            diffEngine.LogError(String.Format(CultureInfo.InvariantCulture, MigrationToolkitResources.WitDiffResultWorkItemAttachmentMissingDetail,
                                                              missingAttachment));
                        }
                    }

                    if (diffPair.DiffAttachments.Count > 0)
                    {
                        diffEngine.LogError(MigrationToolkitResources.WitDiffResultWorkItemAttachmentDiffHeader);
                        foreach (WitDiffAttachment diffAttachment in diffPair.DiffAttachments)
                        {
                            diffEngine.LogError(String.Format(CultureInfo.InvariantCulture, MigrationToolkitResources.WitDiffResultWorkItemAttachmentDiffDetail,
                                                              diffAttachment.SourceAttachmentName, diffAttachment.FieldName, diffAttachment.SourceValue, diffAttachment.TargetValue));
                        }
                    }

                    if (diffPair.MissingLinks.Count > 0)
                    {
                        diffEngine.LogError(MigrationToolkitResources.WitDiffResultWorkItemLinkMissingHeader);
                        foreach (string missingLink in diffPair.MissingLinks)
                        {
                            diffEngine.LogError(String.Format(CultureInfo.InvariantCulture, MigrationToolkitResources.WitDiffResultWorkItemLinkMissingDetail,
                                                              missingLink));
                        }
                    }

                    if (diffPair.DiffLinks.Count > 0)
                    {
                        diffEngine.LogError(MigrationToolkitResources.WitDiffResultWorkItemLinkDiffHeader);
                        foreach (WitDiffLink diffLink in diffPair.DiffLinks)
                        {
                            diffEngine.LogError(String.Format(CultureInfo.InvariantCulture, MigrationToolkitResources.WitDiffResultWorkItemLinkDiffDetail,
                                                              diffLink.FieldName, diffLink.SourceValue, diffLink.TargetValue));
                        }
                    }
                }
            }

            if (m_processingErrors.Count > 0)
            {
                diffEngine.LogError(MigrationToolkitResources.WitDiffResultWorkItemErrorsHeader);
                foreach (string error in m_processingErrors)
                {
                    diffEngine.LogError(error);
                }
            }
            diffEngine.LogInfo(MigrationToolkitResources.WitDiffResultReportSeparator);
        }
        public bool VerifyContentsMatch(string sourceVersion, string targetVersion)
        {
            Stopwatch stopWatch = Stopwatch.StartNew();

            Trace.WriteLine(String.Format(CultureInfo.InvariantCulture,
                                          "Entering VCDiffComparer.VerifyContentsMatch: sourceVersion: {0}, targetVersion: {1}",
                                          sourceVersion == null ? "latest" : sourceVersion,
                                          targetVersion == null ? "latest" : targetVersion));

            List <IVCDiffItem> sourceRootDiffItems = new List <IVCDiffItem>();
            List <IVCDiffItem> targetRootDiffItems = new List <IVCDiffItem>();

            bool contentMatch     = true;
            int  foldersProcessed = 0;
            int  filesProcessed   = 0;

            try
            {
                Stack <IVCDiffItem> sourceFolders = new Stack <IVCDiffItem>();
                Queue <IVCDiffItem> sourceFiles   = new Queue <IVCDiffItem>();

                Dictionary <string, IVCDiffItem> targetFolders = new Dictionary <string, IVCDiffItem>(StringComparer.InvariantCultureIgnoreCase);
                Dictionary <string, IVCDiffItem> targetFiles   = new Dictionary <string, IVCDiffItem>(StringComparer.InvariantCultureIgnoreCase);

                List <string> sourceCloakList = new List <string>();
                List <string> targetCloakList = new List <string>();

                foreach (var filterPair in m_serverDiffEngine.Session.Filters.FilterPair)
                {
                    if (filterPair.Neglect)
                    {
                        // TODO: Need to deal with translating paths for cloaked filter pairs into the canonical relative form used by IVCDiffItem.Path !!!
                        sourceCloakList.Add(GetSourceFilterString(filterPair));
                        targetCloakList.Add(GetTargetFilterString(filterPair));
                    }
                }

                foreach (var filterPair in m_serverDiffEngine.Session.Filters.FilterPair)
                {
                    if (!filterPair.Neglect)
                    {
                        sourceFolders.Clear();
                        sourceFiles.Clear();
                        targetFolders.Clear();
                        targetFiles.Clear();

                        // Always go 1 level down to avoid too large query
                        string      sourceFilterString = GetSourceFilterString(filterPair);
                        IVCDiffItem sourceDiffRootItem = SourceVCDiffProvider.InitializeForDiff(sourceFilterString, sourceVersion);
                        if (sourceDiffRootItem != null)
                        {
                            if (sourceDiffRootItem.VCItemType == VCItemType.Folder)
                            {
                                sourceFolders.Push(sourceDiffRootItem);
                            }
                            else
                            {
                                sourceFiles.Enqueue(sourceDiffRootItem);
                            }
                            sourceRootDiffItems.Add(sourceDiffRootItem);
                        }

                        string      targetFilterString = GetTargetFilterString(filterPair);
                        IVCDiffItem targetDiffRootItem = TargetVCDiffProvider.InitializeForDiff(targetFilterString, targetVersion);
                        if (targetDiffRootItem != null)
                        {
                            if (targetDiffRootItem.VCItemType == VCItemType.Folder)
                            {
                                targetFolders.Add(targetDiffRootItem.ServerPath, targetDiffRootItem);
                            }
                            else
                            {
                                targetFiles.Add(targetDiffRootItem.ServerPath, targetDiffRootItem);
                            }
                            targetRootDiffItems.Add(targetDiffRootItem);
                        }

                        while (sourceFiles.Count > 0 | sourceFolders.Count > 0 | targetFiles.Count > 0 | targetFolders.Count > 0)
                        {
                            while (sourceFiles.Count > 0)
                            {
                                IVCDiffItem sourceItem = sourceFiles.Dequeue();
                                if (sourceItem.VCItemType != VCItemType.File)
                                {
                                    Debug.Fail("VerifyContentMatch: Found IVCDiffItem that is not type File in the sourceFiles queue");
                                    continue;
                                }
                                string targetPath = TranslationService.GetMappedPath(sourceItem.ServerPath, new Guid(m_serverDiffEngine.Session.LeftMigrationSourceUniqueId));

                                if (targetPath == null || !targetFiles.ContainsKey(targetPath))
                                {
                                    m_serverDiffEngine.LogError(string.Format(CultureInfo.InvariantCulture, ServerDiffResources.ItemOnlyFoundOnSource, sourceItem.ServerPath));
                                    contentMatch = false;
                                }
                                else
                                {
                                    bool fileContentsMatch = ContentsMatch(sourceItem.HashValue, targetFiles[targetPath].HashValue);
                                    if (fileContentsMatch)
                                    {
                                        m_serverDiffEngine.LogVerbose(String.Format(CultureInfo.InvariantCulture, ServerDiffResources.FilesMatch,
                                                                                    sourceItem.ServerPath, targetPath));
                                    }
                                    else
                                    {
                                        contentMatch = false;
                                        m_serverDiffEngine.LogError(string.Format(CultureInfo.InvariantCulture, ServerDiffResources.ItemContentDoesNotMatch, sourceItem.ServerPath));
                                    }
                                    targetFiles.Remove(targetPath);
                                }
                                filesProcessed++;
                            }

                            foreach (KeyValuePair <string, IVCDiffItem> remainingFile in targetFiles)
                            {
                                m_serverDiffEngine.LogError(string.Format(CultureInfo.InvariantCulture, ServerDiffResources.ItemOnlyFoundOnTarget, remainingFile.Key));
                                contentMatch = false;
                            }

                            Debug.Assert(sourceFiles.Count == 0);
                            targetFiles.Clear();

                            if (sourceFolders.Count > 0)
                            {
                                IVCDiffItem sourceFolder = sourceFolders.Pop();
                                m_serverDiffEngine.LogVerbose(string.Format(CultureInfo.InvariantCulture, ServerDiffResources.ProcessingSourceFolder, sourceFolder.ServerPath));

                                string targetFolder = TranslationService.GetMappedPath(sourceFolder.ServerPath, new Guid(m_serverDiffEngine.Session.LeftMigrationSourceUniqueId));

                                if (targetFolder != null && targetFolders.ContainsKey(targetFolder))
                                {
                                    // Always go 1 level down to avoid too large query
                                    IEnumerable <IVCDiffItem> sourceDiffItems = SourceVCDiffProvider.GetFolderSubDiffItems(sourceFolder);
                                    foreach (IVCDiffItem diffItem in sourceDiffItems)
                                    {
                                        if (isCloaked(SourceVCDiffProvider, diffItem, sourceCloakList))
                                        {
                                            continue;
                                        }
                                        if (diffItem.VCItemType == VCItemType.File)
                                        {
                                            sourceFiles.Enqueue(diffItem);
                                        }
                                        else
                                        {
                                            sourceFolders.Push(diffItem);
                                        }
                                    }

                                    IEnumerable <IVCDiffItem> targetDiffItems = TargetVCDiffProvider.GetFolderSubDiffItems(targetFolders[targetFolder]);
                                    foreach (IVCDiffItem diffItem in targetDiffItems)
                                    {
                                        if (isCloaked(TargetVCDiffProvider, diffItem, targetCloakList))
                                        {
                                            continue;
                                        }
                                        if (diffItem.VCItemType == VCItemType.File)
                                        {
                                            if (!targetFiles.ContainsKey(diffItem.ServerPath))
                                            {
                                                targetFiles.Add(diffItem.ServerPath, diffItem);
                                            }
                                        }
                                        else
                                        {
                                            if (!targetFolders.ContainsKey(diffItem.ServerPath))
                                            {
                                                targetFolders.Add(diffItem.ServerPath, diffItem);
                                            }
                                        }
                                    }
                                    targetFolders.Remove(targetFolder);
                                    if (++foldersProcessed % 100 == 0)
                                    {
                                        m_serverDiffEngine.LogInfo(String.Format(CultureInfo.InvariantCulture, "Processed {0} source folders containing {1} files ...",
                                                                                 foldersProcessed, filesProcessed));
                                    }
                                }
                                else
                                {
                                    m_serverDiffEngine.LogError(string.Format(CultureInfo.InvariantCulture, ServerDiffResources.ItemOnlyFoundOnSource, sourceFolder.ServerPath));
                                    contentMatch = false;
                                }
                            }
                            else
                            {
                                foreach (KeyValuePair <string, IVCDiffItem> remainingFolder in targetFolders)
                                {
                                    m_serverDiffEngine.LogError(string.Format(CultureInfo.InvariantCulture, ServerDiffResources.ItemOnlyFoundOnTarget, remainingFolder.Key));
                                    contentMatch = false;
                                }
                                targetFolders.Clear();
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Trace.WriteLine("Exception occurred while verifying contents match: " + e.ToString());
                throw;
            }
            finally
            {
                if (SourceVCDiffProvider != null)
                {
                    foreach (IVCDiffItem sourceRootDiffItem in sourceRootDiffItems)
                    {
                        SourceVCDiffProvider.Cleanup(sourceRootDiffItem);
                    }
                }
                if (TargetVCDiffProvider != null)
                {
                    foreach (IVCDiffItem targetRootDiffItem in targetRootDiffItems)
                    {
                        TargetVCDiffProvider.Cleanup(targetRootDiffItem);
                    }
                }
                stopWatch.Stop();
                m_serverDiffEngine.LogInfo(String.Format(CultureInfo.InvariantCulture, ServerDiffResources.VCServerDiffTimeToRun,
                                                         stopWatch.Elapsed.TotalSeconds));
                m_serverDiffEngine.LogInfo(String.Format(CultureInfo.InvariantCulture, "Processed a total of {0} source folders containing {1} files",
                                                         foldersProcessed, filesProcessed));
            }

            Trace.WriteLine("VCDiffComparer.VerifyContentsMatch result: " + contentMatch);

            return(contentMatch);
        }