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

yangziwen / diff-check / #25

30 Sep 2026 08:04AM UTC coverage: 55.759% (-12.8%) from 68.559%
#25

push

yangziwen
test: 补充 diff-pmd 和 diff-jacoco-maven-plugin 模块测试

diff-pmd(5 个用例):
- DiffLineFilterTest:变更行内违规放行、未变更行过滤、
  不在 diff 内的文件过滤(mock DiffEntryWrapper/RuleViolation)
- MainSmokeTest:端到端冒烟,空 catch 触发 EmptyCatchBlock,
  断言 run() 退出码 4;干净代码断言退出码 0

diff-jacoco-maven-plugin(11 个用例):
- FilterUtilTest:getClassPath 默认包/带包名转换、
  collectLineNumberNodeList 行号节点收集与 next 链
- DiffFilterTest:变更行内不忽略、diff 外文件整方法忽略、
  src/test/java 下文件忽略(临时目录 canonical path 处理 macOS /var 符号链接)
- PersonFilterTest:模块前缀映射(含多层嵌套)、模块外跳过、
  单模块工程空前缀、PersonInfo 匹配规则、AUTHOR/COMMITTER 分派

同时移除 diff-jacoco-maven-plugin pluginManagement 中
surefire 2.9 版本钉子(覆盖根 pom 3.2.5 导致 JUnit 5 测试不执行),
补充 mockito-core 测试依赖。

305 of 547 relevant lines covered (55.76%)

0.56 hits per line

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

40.98
/diff-core/src/main/java/io/github/yangziwen/diff/calculate/DiffHelper.java
1
package io.github.yangziwen.diff.calculate;
2

3
import java.lang.reflect.Field;
4
import java.lang.reflect.Method;
5
import java.util.Collection;
6

7
import org.eclipse.jgit.diff.ContentSource;
8
import org.eclipse.jgit.diff.DiffEntry;
9
import org.eclipse.jgit.errors.AmbiguousObjectException;
10
import org.eclipse.jgit.errors.LargeObjectException;
11
import org.eclipse.jgit.errors.MissingObjectException;
12
import org.eclipse.jgit.lib.AbbreviatedObjectId;
13
import org.eclipse.jgit.lib.AnyObjectId;
14
import org.eclipse.jgit.lib.Constants;
15
import org.eclipse.jgit.lib.FileMode;
16
import org.eclipse.jgit.lib.ObjectId;
17
import org.eclipse.jgit.lib.ObjectLoader;
18
import org.eclipse.jgit.lib.ObjectReader;
19

20
/**
21
 * The diff helper
22
 * Provide some useful methods to help finish diff calculation
23
 *
24
 * @author yangziwen
25
 */
26
public class DiffHelper {
27

28
    public static final int DEFAULT_BIG_FILE_THRESHOLD = 10 * 1024 * 1024;
29

30
    private static final Field DIFF_ENTRY_OLD_ID_FIELD = getField(DiffEntry.class, "oldId");
1 ✔
31

32
    private static final Field DIFF_ENTRY_NEW_ID_FIELD = getField(DiffEntry.class, "newId");
1 ✔
33

34
    private static final Method DIFF_ENTRY_ADD_METHOD = getDiffEntryAddMethod();
1 ✔
35

36
    private static final Method DIFF_ENTRY_MODIFY_METHOD = getDiffEntryModifyMethod();
1 ✔
37

38
    /**
39
     * 空内容,用于两种场景:
40
     * 1. 内容确实不存在(GITLINK 指向 zeroId、MISSING mode、非 BLOB 类型);
41
     * 2. 文件过大超过 bigFileThreshold 无法加载内容。
42
     * 注意:场景 2 下新旧两侧均为空内容,edit 列表为空,
43
     * 该文件实质上被排除在 diff 行过滤之外(行级检查不会覆盖它)。
44
     */
45
    private static final byte[] EMPTY = new byte[] {};
1 ✔
46

47
    private DiffHelper() {}
48

49
    /**
50
     * read content from the diff entry
51
     *
52
     * @param entry
53
     * @param side
54
     * @param reader
55
     * @param bigFileThreshold
56
     * @return
57
     * @throws Exception
58
     */
59
    public static byte[] open(
60
            DiffEntry entry,
61
            DiffEntry.Side side,
62
            ObjectReader reader,
63
            int bigFileThreshold) throws Exception {
64
        if (entry.getMode(side) == FileMode.GITLINK) {
1 ✔
65
            return writeGitLinkText(entry.getId(side));
×
66
        }
67
        if (entry.getMode(side) == FileMode.MISSING) {
1 ✔
68
            return EMPTY;
1 ✔
69
        }
70
        if (entry.getMode(side).getObjectType() != Constants.OBJ_BLOB) {
1 ✔
71
            return EMPTY;
×
72
        }
73
        AbbreviatedObjectId id = entry.getId(side);
1 ✔
74
        if (!id.isComplete()) {
1 ✔
75
            Collection<ObjectId> ids = reader.resolve(id);
×
76
            if (ids.size() == 1) {
×
77
                id = AbbreviatedObjectId.fromObjectId(ids.iterator().next());
×
78
                switch (side) {
×
79
                    case OLD:
80
                        DIFF_ENTRY_OLD_ID_FIELD.set(entry, id);
×
81
                        break;
×
82
                    case NEW:
83
                        DIFF_ENTRY_NEW_ID_FIELD.set(entry, id);
×
84
                        break;
×
85
                    default:
86
                        break;
×
87
                }
88
            }
89
            else if (ids.size() == 0) {
×
90
                throw new MissingObjectException(id, Constants.OBJ_BLOB);
×
91
            }
92
            else {
93
                throw new AmbiguousObjectException(id, ids);
×
94
            }
95
        }
96
        ContentSource cs = ContentSource.create(reader);
1 ✔
97
        try {
98
            ObjectLoader ldr = new ContentSource.Pair(cs, cs).open(side, entry);
1 ✔
99
            return ldr.getBytes(bigFileThreshold);
1 ✔
100

101
        } catch (LargeObjectException.ExceedsLimit overLimit) {
×
102
            // 文件过大,按空内容处理,产出空 edit 列表(见 EMPTY 注释)
103
            return EMPTY;
×
104

105
        } catch (LargeObjectException.ExceedsByteArrayLimit overLimit) {
×
106
            return EMPTY;
×
107

108
        } catch (LargeObjectException.OutOfMemory tooBig) {
×
109
            return EMPTY;
×
110

111
        } catch (LargeObjectException tooBig) {
×
112
            tooBig.setObjectId(id.toObjectId());
×
113
            throw tooBig;
×
114
        }
115
    }
116

117
    private static byte[] writeGitLinkText(AbbreviatedObjectId id) {
118
        if (ObjectId.zeroId().equals(id.toObjectId())) {
×
119
            return EMPTY;
×
120
        }
121
        return Constants.encodeASCII("Subproject commit " + id.name() + "\n");
×
122
    }
123

124
    private static <T> Field getField(Class<T> clazz, String fieldName) {
125
        try {
126
            Field field = clazz.getDeclaredField(fieldName);
1 ✔
127
            field.setAccessible(true);
1 ✔
128
            return field;
1 ✔
129
        } catch (Exception e) {
×
130
            throw new RuntimeException(e);
×
131
        }
132
    }
133

134
    public static DiffEntry createAddDiffEntry(String path, AnyObjectId id) {
135
        try {
136
            return (DiffEntry) DIFF_ENTRY_ADD_METHOD.invoke(null, path, id);
1 ✔
137
        } catch (Exception e) {
×
138
            throw new RuntimeException(e);
×
139
        }
140
    }
141

142
    public static DiffEntry createModifyDiffEntry(String path) {
143
        try {
144
            return (DiffEntry) DIFF_ENTRY_MODIFY_METHOD.invoke(null, path);
1 ✔
145
        } catch (Exception e) {
×
146
            throw new RuntimeException(e);
×
147
        }
148
    }
149

150
    private static Method getDiffEntryAddMethod() {
151
        Method method;
152
        try {
153
            method = DiffEntry.class.getDeclaredMethod("add", String.class, AnyObjectId.class);
1 ✔
154
            method.setAccessible(true);
1 ✔
155
            return method;
1 ✔
156
        } catch (Exception e) {
×
157
            throw new RuntimeException(e);
×
158
        }
159
    }
160

161
    private static Method getDiffEntryModifyMethod() {
162
        Method method;
163
        try {
164
            method = DiffEntry.class.getDeclaredMethod("modify", String.class);
1 ✔
165
            method.setAccessible(true);
1 ✔
166
            return method;
1 ✔
167
        } catch (Exception e) {
×
168
            throw new RuntimeException(e);
×
169
        }
170
    }
171

172
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc