View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.coverage.reporting.sourceFiles;
7   
8   import edu.umd.cs.findbugs.annotations.NonNull;
9   import edu.umd.cs.findbugs.annotations.Nullable;
10  
11  import java.io.BufferedReader;
12  import java.io.File;
13  import java.io.FileFilter;
14  import java.io.IOException;
15  import java.nio.charset.StandardCharsets;
16  import java.nio.file.Files;
17  import java.nio.file.Path;
18  import java.util.List;
19  
20  import org.checkerframework.checker.index.qual.NonNegative;
21  
22  public final class InputFile {
23      @NonNull
24      final String filePath;
25      @NonNull
26      private final File sourceFile;
27      @NonNull
28      private final BufferedReader input;
29  
30      @Nullable
31      public static InputFile createIfFileExists(@NonNull List<File> sourceDirs, @NonNull String filePath)
32              throws IOException {
33          File sourceFile = findSourceFile(sourceDirs, filePath);
34          return sourceFile == null ? null : new InputFile(filePath, sourceFile);
35      }
36  
37      @Nullable
38      private static File findSourceFile(@NonNull List<File> sourceDirs, @NonNull String filePath) {
39          int p = filePath.indexOf('/');
40          String topLevelPackage = p < 0 ? "" : filePath.substring(0, p);
41          int n = sourceDirs.size();
42  
43          for (int i = 0; i < n; i++) {
44              File sourceDir = sourceDirs.get(i);
45              File sourceFile = getSourceFile(sourceDir, topLevelPackage, filePath);
46  
47              if (sourceFile != null) {
48                  giveCurrentSourceDirHighestPriority(sourceDirs, i);
49                  addRootSourceDirIfNew(sourceDirs, filePath, sourceFile);
50                  return sourceFile;
51              }
52          }
53  
54          return null;
55      }
56  
57      @Nullable
58      private static File getSourceFile(@NonNull File sourceDir, @NonNull final String topLevelPackage,
59              @NonNull String filePath) {
60          File file = sourceDir.toPath().resolve(filePath).toFile();
61  
62          if (file.exists()) {
63              return file;
64          }
65  
66          File[] subDirs = sourceDir.listFiles((FileFilter) subDir -> subDir.isDirectory() && !subDir.isHidden()
67                  && !subDir.getName().equals(topLevelPackage));
68  
69          if (subDirs != null && subDirs.length > 0) {
70              for (File subDir : subDirs) {
71                  File sourceFile = getSourceFile(subDir, topLevelPackage, filePath);
72  
73                  if (sourceFile != null) {
74                      return sourceFile;
75                  }
76              }
77          }
78  
79          return null;
80      }
81  
82      private static void giveCurrentSourceDirHighestPriority(@NonNull List<File> sourceDirs,
83              @NonNegative int currentSourceDirIndex) {
84          if (currentSourceDirIndex > 0) {
85              File firstSourceDir = sourceDirs.get(0);
86              File currentSourceDir = sourceDirs.get(currentSourceDirIndex);
87  
88              if (!firstSourceDir.getPath().startsWith(currentSourceDir.getPath())) {
89                  sourceDirs.set(currentSourceDirIndex, firstSourceDir);
90                  sourceDirs.set(0, currentSourceDir);
91              }
92          }
93      }
94  
95      private static void addRootSourceDirIfNew(@NonNull List<File> sourceDirs, @NonNull String filePath,
96              @NonNull File sourceFile) {
97          String sourceFilePath = sourceFile.getPath();
98          String sourceRootDir = sourceFilePath.substring(0, sourceFilePath.length() - filePath.length());
99          File newSourceDir = Path.of(sourceRootDir).toFile();
100 
101         if (!sourceDirs.contains(newSourceDir)) {
102             sourceDirs.add(0, newSourceDir);
103         }
104     }
105 
106     private InputFile(@NonNull String filePath, @NonNull File sourceFile) throws IOException {
107         this.filePath = filePath;
108         this.sourceFile = sourceFile;
109         input = Files.newBufferedReader(sourceFile.toPath(), StandardCharsets.UTF_8);
110     }
111 
112     @NonNull
113     String getSourceFileName() {
114         return sourceFile.getName();
115     }
116 
117     @NonNull
118     String getSourceFilePath() {
119         String path = sourceFile.getPath();
120         return path.startsWith("..") ? path.substring(3) : path;
121     }
122 
123     @Nullable
124     String nextLine() throws IOException {
125         return input.readLine();
126     }
127 
128     void close() throws IOException {
129         input.close();
130     }
131 }