Ejemplo n.º 1
0
        public IEnumerable<Violation> Apply(TestCase testCase)
        {
            var calledAssertingMethods = testCase.GetCalledAssertingMethods();
            var tracker = new MethodValueTracker(testCase.TestMethod);

            // For each asserting method with >= 1 parameters:
            foreach (var cm in calledAssertingMethods)
            {
                var methodRef = cm.MethodReference;
                var parameterPurposes = testCase.Framework.GetParameterPurposes(methodRef);
                if (!IsSingleTruthCheckingMethod(methodRef, parameterPurposes))
                    continue;

                foreach (var valueGraph in tracker.ValueGraphs)
                {
                    IList<MethodValueTracker.Value> consumedValues =
                        tracker.GetConsumedValues(valueGraph, cm.Instruction).ToList();
                    if (consumedValues.Count == 0)
                        continue; // not part of value graph
                    var interestingValue = consumedValues[0];
                    var producers = UltimateProducers(interestingValue);
                    if (producers.Count > 1)
                    {
                        yield return new Violation(this, testCase, cm.Instruction, string.Format("{0}.{1} performs a boolean test on a composite boolean value",
                            cm.MethodReference.DeclaringType.Name,
                            cm.MethodReference.Name));
                    }
                }
            }
        }
        private static int CountAssertsThatDontOccurInAllInstructionPaths(TestCase testCase, IEnumerable<IList<Instruction>> paths)
        {
            //TODO: Copied from LocalExpectationRule, need a better abstraction for this!
            var calledAssertingMethods = testCase.GetCalledAssertingMethods();
            var calledAssertingMethodsWithInstruction =
                testCase.TestMethod.CalledMethods().Where(calledAssertingMethods.Contains);

            return
                calledAssertingMethodsWithInstruction.Count(cmi => paths.Any(path => !path.Contains(cmi.Instruction)));
        }
Ejemplo n.º 3
0
        public IEnumerable<Violation> Apply(TestCase testCase)
        {
            // It seems as if unhandled return values are popped off the stack
            // immediately via an explicit "pop" instruction.

            // We exclude asserting methods to avoid getting a violation for Assert.Throws (or Assert.Catch),
            // which returns the exception.
            var calledMethods = testCase.TestMethod.CalledMethods();
            var asserting = testCase.GetCalledAssertingMethods();

            var callingNonVoidInstructions = calledMethods
                .Where(cm => !asserting.Contains(cm))
                .Select(cm => cm.Instruction);

            var unhandled = callingNonVoidInstructions.Where(ins => ins.Next.OpCode == OpCodes.Pop).ToList();
            if (unhandled.Count == 1 && testCase.Framework.HasExpectedException(testCase.TestMethod))
                yield break; // last unhandled value is ok!
            foreach (var instr in unhandled)
            {
                yield return new Violation(this, testCase, instr, CreateViolationMessage(instr));
            }
        }
Ejemplo n.º 4
0
        public IEnumerable<Violation> Apply(TestCase testCase)
        {
            if (!testCase.TestMethod.DeclaringType.Module.HasSymbols)
                yield break; //TODO: decide what to do here!

            var assertingMethods = testCase.GetCalledAssertingMethods();

            // Note: The Mono compiler appears to emit multiple sequence points with the same start line,
            // i.e. there are multiple instructions with sequence points that refer to the same line.
            // Therefore, let's store line numbers and associate line numbers with asserting calls.

            var sequencePointsStartLines = new SortedSet<int>();
            var assertingSequencePointsStartLines = new SortedSet<int>();

            var tm = testCase.TestMethod;
            foreach (var ins in tm.Body.Instructions)
            {
                var sp = ins.SequencePoint;
                if (sp != null && IsSignificantSequencePoint(ins, sp))
                {
                    sequencePointsStartLines.Add(sp.StartLine);
                }
                if (sequencePointsStartLines.Count > 0 && IsAssertCall(ins, assertingMethods))
                {
                    // As sequence point, use the last one added, which isn't necessarily sp,
                    // since the asserting instruction may lack sequence point.
                    var lastSpLineNumber = sequencePointsStartLines.Last();
                    assertingSequencePointsStartLines.Add(lastSpLineNumber);
                }
            }

            if (assertingSequencePointsStartLines.Count == 0)
                yield break; // this rule doesn't apply
            // If the X asserting sps are the X last ones, then it's ok!
            if (sequencePointsStartLines.EndsWith(assertingSequencePointsStartLines))
                yield break;
            yield return new Violation(this, testCase);
        }
Ejemplo n.º 5
0
        public IEnumerable<Violation> Apply(TestCase testCase)
        {
            // Store the framework so that we don't have to pass it around everywhere.
            _framework = testCase.Framework;

            var calledAssertingMethods = testCase.GetCalledAssertingMethods();
            var tracker = new MethodValueTracker(testCase.TestMethod);

            var whitelistedFields = FindWhitelistedFields(testCase.TestMethod.DeclaringType);

            // For each asserting method with >= 1 parameters:
            foreach (var cm in calledAssertingMethods.Where(cm => cm.MethodDefinition.HasParameters))
            {
                var method = cm.MethodDefinition;
                //TODO: if the method is a helper, we need to "unfold" the helper
                // to get to the real asserting methods, and this will require us
                // to join value-generation graphs across method calls...
                var paramPurposes = _framework.GetParameterPurposes(method);
                if (paramPurposes == null) continue; // unknown method, rule does not apply

                foreach (var valueGraph in tracker.ValueGraphs)
                {
                    IList<MethodValueTracker.Value> consumedValues = tracker.GetConsumedValues(valueGraph, cm.Instruction).ToList();
                    if (consumedValues.Count == 0)
                        continue; // not part of value graph

                    // Build a list of arguments with the details we need to know if the rule applies.
                    var arguments = method.Parameters
                        .Select((p, index) => new ArgumentDetails { Method = method, Index = index, Purpose = paramPurposes[index], ConsumedValue = consumedValues[index] }).ToList();

                    // Handle cases like Assert.IsTrue(x == 5) by expanding arguments
                    ExpandIfSingleTruthCheckingMethod(method, ref arguments);

                    // We're only interested in arguments that represent expectations!
                    var interestingArguments = arguments.Where(a => IsPerhapsExpectation(a.Purpose)).ToList();

                    // This might happen with for example Assert.Fail("some reason").
                    if (interestingArguments.Count == 0)
                        continue;

                    // Add in the "forbidden producer", if any, for each argument. A forbidden producer is an
                    // instruction that generates a value externally, such as a call.
                    interestingArguments = interestingArguments.Select(
                            a => { a.ForbiddenProducer = FirstForbiddenProducer(valueGraph, a.ConsumedValue, whitelistedFields); return a; }).ToList();

                    // If there is at least one locally produced argument, the rule doesn't apply.
                    if (interestingArguments.Any(IsLocallyProduced))
                        continue;

                    if (interestingArguments.All(a => a.Purpose == ParameterPurpose.ExpectedOrActual))
                    {
                        // Since we don't know exactly which parameter that represents the expectation, we
                        // just generate a single violation.
                        yield return new Violation(this, testCase, interestingArguments[0].ConsumedValue.Consumer,
                            CreateViolationMessageForUncertainCase(interestingArguments[0]));
                        continue;
                    }

                    foreach (var a in interestingArguments.Where(IsExternallyProduced))
                    {

                        // Generate a violation at the location of the forbidden producer!
                        yield return new Violation(this, testCase, a.ForbiddenProducer, CreateViolationMessage(a));
                    }
                }
            }
        }
Ejemplo n.º 6
0
 protected override int GenerateValue(TestCase tc, Features f)
 {
     return tc.GetCalledAssertingMethods().Count;
 }