• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / jmockit1 / 533

26 Nov 2025 03:18PM UTC coverage: 72.291% (+0.09%) from 72.2%
533

Pull #422

github

web-flow
Merge 447b13428 into f3aed3cfe
Pull Request #422: Restore @Mock invocation constraints and fix MockedTypeCascade concurrency

5732 of 8416 branches covered (68.11%)

Branch coverage included in aggregate %.

78 of 98 new or added lines in 6 files covered. (79.59%)

6 existing lines in 1 file now uncovered.

11998 of 16110 relevant lines covered (74.48%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.55
/main/src/main/java/mockit/internal/faking/FakeMethodCollector.java
1
/*
2
 * MIT License
3
 * Copyright (c) 2006-2025 JMockit developers
4
 * See LICENSE file for full license text.
5
 */
6
package mockit.internal.faking;
7

8
import static mockit.asm.jvmConstants.Access.ABSTRACT;
9
import static mockit.asm.jvmConstants.Access.BRIDGE;
10
import static mockit.asm.jvmConstants.Access.NATIVE;
11
import static mockit.asm.jvmConstants.Access.SYNTHETIC;
12

13
import edu.umd.cs.findbugs.annotations.NonNull;
14
import edu.umd.cs.findbugs.annotations.Nullable;
15

16
import java.lang.reflect.Method;
17
import java.util.EnumSet;
18
import java.util.List;
19

20
import mockit.Mock;
21
import mockit.MockUp;
22
import mockit.asm.metadata.ClassMetadataReader;
23
import mockit.asm.metadata.ClassMetadataReader.Attribute;
24
import mockit.asm.metadata.ClassMetadataReader.MethodInfo;
25
import mockit.asm.types.JavaType;
26
import mockit.internal.ClassFile;
27
import mockit.internal.faking.FakeMethods.FakeMethod;
28
import mockit.internal.util.ClassLoad;
29
import mockit.internal.util.TypeDescriptor;
30

31
/**
32
 * Responsible for collecting the signatures of all methods defined in a given fake class which are explicitly annotated
33
 * as {@link Mock fakes}.
34
 */
35
final class FakeMethodCollector {
36
    private static final int INVALID_METHOD_ACCESSES = BRIDGE + SYNTHETIC + ABSTRACT + NATIVE;
37
    private static final EnumSet<Attribute> ANNOTATIONS = EnumSet.of(Attribute.Annotations);
1✔
38

39
    @NonNull
40
    private final FakeMethods fakeMethods;
41
    private boolean collectingFromSuperClass;
42

43
    FakeMethodCollector(@NonNull FakeMethods fakeMethods) {
1✔
44
        this.fakeMethods = fakeMethods;
1✔
45
    }
1✔
46

47
    void collectFakeMethods(@NonNull Class<?> fakeClass) {
48
        ClassLoad.registerLoadedClass(fakeClass);
1✔
49
        fakeMethods.setFakeClassInternalName(JavaType.getInternalName(fakeClass));
1✔
50

51
        Class<?> classToCollectFakesFrom = fakeClass;
1✔
52

53
        do {
54
            byte[] classfileBytes = ClassFile.readBytesFromClassFile(classToCollectFakesFrom);
1✔
55
            ClassMetadataReader cmr = new ClassMetadataReader(classfileBytes, ANNOTATIONS);
1✔
56
            List<MethodInfo> methods = cmr.getMethods();
1✔
57
            addFakeMethods(classToCollectFakesFrom, methods);
1✔
58

59
            classToCollectFakesFrom = classToCollectFakesFrom.getSuperclass();
1✔
60
            collectingFromSuperClass = true;
1✔
61
        } while (classToCollectFakesFrom != MockUp.class);
1✔
62
    }
1✔
63

64
    private void addFakeMethods(@NonNull Class<?> fakeClass, @NonNull List<MethodInfo> methods) {
65
        for (MethodInfo method : methods) {
1✔
66
            int access = method.accessFlags;
1✔
67

68
            if ((access & INVALID_METHOD_ACCESSES) == 0 && method.isMethod() && method.hasAnnotation("Lmockit/Mock;")) {
1✔
69
                FakeMethod fakeMethod = fakeMethods.addMethod(collectingFromSuperClass, access, method.name,
1✔
70
                        method.desc);
71

72
                if (fakeMethod != null) {
1!
73
                    FakeState fakeState = createFakeStateIfRequired(fakeMethod);
1✔
74
                    applyInvocationConstraintsIfAny(fakeClass, method, fakeMethod, fakeState);
1✔
75
                }
76
            }
77
        }
1✔
78
    }
1✔
79

80
    @Nullable
81
    private FakeState createFakeStateIfRequired(@NonNull FakeMethod fakeMethod) {
82
        if (!fakeMethod.requiresFakeState()) {
1✔
83
            return null;
1✔
84
        }
85

86
        FakeState fakeState = new FakeState(fakeMethod);
1✔
87
        fakeMethods.addFakeState(fakeState);
1✔
88
        return fakeState;
1✔
89
    }
90

91
    private void applyInvocationConstraintsIfAny(@NonNull Class<?> fakeClass, @NonNull MethodInfo methodInfo,
92
            @NonNull FakeMethod fakeMethod, @Nullable FakeState existingFakeState) {
93
        Method javaMethod = findJavaMethod(fakeClass, methodInfo);
1✔
94
        Mock annotation = javaMethod.getAnnotation(Mock.class);
1✔
95

96
        if (annotation == null) {
1!
NEW
97
            return;
×
98
        }
99

100
        int expectedInvocations = annotation.invocations();
1✔
101
        int minInvocations = annotation.minInvocations();
1✔
102
        int maxInvocations = annotation.maxInvocations();
1✔
103

104
        boolean hasConstraints = expectedInvocations >= 0 || minInvocations > 0 || maxInvocations >= 0;
1✔
105

106
        if (!hasConstraints) {
1✔
107
            return;
1✔
108
        }
109

110
        FakeState fakeState = existingFakeState;
1✔
111

112
        if (fakeState == null) {
1✔
113
            fakeState = new FakeState(fakeMethod);
1✔
114
        }
115

116
        if (expectedInvocations >= 0) {
1✔
117
            fakeState.setExpectedInvocations(expectedInvocations);
1✔
118
        }
119

120
        if (minInvocations > 0) {
1✔
121
            fakeState.setMinExpectedInvocations(minInvocations);
1✔
122
        }
123

124
        if (maxInvocations >= 0) {
1✔
125
            fakeState.setMaxExpectedInvocations(maxInvocations);
1✔
126
        }
127

128
        if (existingFakeState == null) {
1✔
129
            fakeMethods.addFakeState(fakeState);
1✔
130
        }
131
    }
1✔
132

133
    @NonNull
134
    private Method findJavaMethod(@NonNull Class<?> fakeClass, @NonNull MethodInfo methodInfo) {
135
        Class<?>[] parameterTypes = TypeDescriptor.getParameterTypes(methodInfo.desc);
1✔
136

137
        try {
138
            Method method = fakeClass.getDeclaredMethod(methodInfo.name, parameterTypes);
1✔
139

140
            try {
141
                method.setAccessible(true);
1✔
NEW
142
            } catch (SecurityException ignore) {
×
143
                // Best-effort only; access will still work for public/protected members.
144
            }
1✔
145

146
            return method;
1✔
NEW
147
        } catch (NoSuchMethodException e) {
×
NEW
148
            throw new IllegalStateException(
×
NEW
149
                    "Unable to resolve @Mock method " + fakeClass.getName() + '#' + methodInfo.name, e);
×
150
        }
151
    }
152
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc