private bool ProcessQaError([NotNull] QaError qaError)
        {
            Assert.ArgumentNotNull(qaError, nameof(qaError));

            if (_msg.IsVerboseDebugEnabled)
            {
                _msg.DebugFormat("Issue found: {0}", qaError);
            }

            // TODO: Consider checking basic relevance (inside test perimeter?) here

            var eventArgs = new QaErrorEventArgs(qaError);

            QaError?.Invoke(this, eventArgs);

            if (eventArgs.Cancel)
            {
                return(false);
            }

            ITest test = qaError.Test;
            QualityConditionVerification conditionVerification =
                GetQualityConditionVerification(test);
            QualityCondition qualityCondition = conditionVerification.QualityCondition;

            Assert.NotNull(qualityCondition, "no quality condition for verification");

            StopInfo stopInfo = null;

            if (conditionVerification.StopOnError)
            {
                stopInfo = new StopInfo(qualityCondition, qaError.Description);

                foreach (InvolvedRow involvedRow in qaError.InvolvedRows)
                {
                    RowsWithStopConditions.Add(involvedRow.TableName,
                                               involvedRow.OID, stopInfo);
                }
            }

            if (!conditionVerification.AllowErrors)
            {
                conditionVerification.Fulfilled = false;

                if (stopInfo != null)
                {
                    // it's a stop condition, and it is a 'hard' condition, and the error is
                    // relevant --> consider the stop situation as sufficiently reported
                    // (no reporting in case of stopped tests required)
                    stopInfo.Reported = true;
                }
            }

            return(true);
        }
        /// <summary>
        /// Handles the TestingRow event of the container.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param>
        /// <remarks>Must be called within dom tx</remarks>
        private void container_TestingRow(object sender, RowEventArgs e)
        {
            if (Cancelled)
            {
                e.Cancel = true;
                return;
            }

            StopInfo stopInfo = RowsWithStopConditions.GetStopInfo(e.Row);

            var test = (ITest)sender;
            TestVerification testVerification = GetTestVerification(test);

            if (stopInfo != null)
            {
                if (!stopInfo.Reported)
                {
                    stopInfo.Reported = TryReportStopInfo(
                        stopInfo, e.Row,
                        testVerification.QualityConditionVerification);
                }

                // cancel further testing on this row
                e.Cancel = true;
                return;
            }

            _currentRow = e.Row;

            if (LocationBasedQualitySpecification != null)
            {
                var feature = e.Row as IFeature;

                if (feature != null &&
                    !LocationBasedQualitySpecification.IsFeatureToBeTested(
                        feature, e.Recycled, e.RecycleUnique,
                        testVerification.QualityCondition, e.IgnoreTestArea))
                {
                    e.Cancel = true;
                }
            }
        }
        public void Execute(IEnumerable <ITest> tests,
                            AreaOfInterest areaOfInterest,
                            CancellationTokenSource cancellationTokenSource)
        {
            Assert.NotNull(TestAssembler, nameof(TestAssembler));

            StartVerification(QualityVerification);

            TimeSpan processorStartTime = Process.GetCurrentProcess().UserProcessorTime;

            CancellationTokenSource = cancellationTokenSource;

            CancellationTokenSource.Token.Register(() => _executeContainer?.StopExecute());

            VerificationTimeStats = new VerificationTimeStats();

            _testPerimeter = areaOfInterest?.Geometry;

            IList <ITest> containerTests = TestAssembler.AssembleTests(
                tests, areaOfInterest, FilterTableRowsUsingRelatedGeometry,
                out IList <TestsWithRelatedGeometry> testsWithRelatedGeometry);

            var container = GetTestContainer(containerTests, AllowEditing, _tileSize,
                                             ForceFullScanForNonContainerTests);

            RowsWithStopConditions.Clear();

            VerifyByRelatedGeometry(testsWithRelatedGeometry);

            if (!Cancelled)
            {
                Verify(container, areaOfInterest);
            }

            EndVerification(QualityVerification, processorStartTime);

            _msg.DebugFormat("Number of rows with stop conditions: {0}",
                             RowsWithStopConditions.Count);
        }