UtilModel { @NotNull @VisibleForPackageGroup public static String getRelativePath( @NotNull String srcPath, @NotNull String dstPath) { Iterator<String> srcIt = Util.splitPath(srcPath).iterator(); Iterator<String> dstIt = Util.splitPath(dstPath).iterator(); List<String> srcOverhang = new ArrayList<String>(); List<String> dstOverhang = new ArrayList<String>(); List<String> dstList = new ArrayList<String>(); boolean stillEqual = true; while (true) { String srcPart = null; String dstPart = null; if (srcIt.hasNext()) srcPart = srcIt.next(); if (dstIt.hasNext()) { dstPart = dstIt.next(); dstList.add(dstPart); } if (srcPart == null && dstPart == null) break; if (stillEqual && !Objects.equal(srcPart, dstPart)) stillEqual = false; if (stillEqual) continue; if (srcPart != null) srcOverhang.add(".."); if (dstPart != null) dstOverhang.add(dstPart); } String path = null; if (srcOverhang.isEmpty()) { if (dstOverhang.isEmpty()) path = Util.joinPath(dstList); else path = Util.joinPath(dstOverhang); } else if (dstOverhang.isEmpty()) path = Util.joinPath(srcOverhang); else path = Util.joinPath(srcOverhang) + "/" + Util.joinPath(dstOverhang); return path; } private  UtilModel(); @NotNull static String getRelativePathIfPossible(@NotNull File file); @NotNull @VisibleForPackageGroup static String getRelativePath(	@NotNull String srcPath,
											@NotNull String dstPath); @NotNull @VisibleForPackageGroup static String getRelativePath(	@NotNull File srcFile,
											@NotNull File dstFile); @VisibleForPackageGroup static void assertDocCount(	Directory luceneDir,
										int expectedCount); @VisibleForPackageGroup static void assertResultCount(	Directory luceneDir,
											String query,
											int expectedCount); @VisibleForPackageGroup static boolean isZipArchive(@NotNull TFile file); @Nullable @VisibleForPackageGroup static File maybeUnpackZipEntry(	@NotNull IndexingConfig config,
											@NotNull File file); static boolean isUnmodifiedArchive(	@NotNull Folder<?, ?> folder,
												@Nullable Long newLastModified); static final void fail(	@NotNull IndexingReporter reporter,
									@NotNull ErrorType type,
									@NotNull TreeNode treeNode,
									@Nullable Throwable cause);  }
@Test public void testGetRelativePath() { String[] tests = { "/path/to/file", "/path/to/file", "/path/to/file", "", "", "", "C:", "C:\\", "C:", "/same/path", "same/path/", "../../../same/path", "/path/to/file", "/path/to/file/and/more", "and/more", "", "some/path", "some/path", "/path/to/file/and/more", "/path/to/file", "../..", "C:\\Windows\\System\\Temp\\", "C:\\Windows\\", "../..", "/path/to/one/file", "/path/to/another/file", "../../another/file", "C:\\Windows\\System", "C:\\Program Files\\DocFetcher", "../../Program Files/DocFetcher", "path/to/file", "some/thing/else", "../../../some/thing/else", "C:", "D:\\Windows\\", "../D:/Windows", }; for (int i = 0; i < tests.length - 2; i += 3) { String src = tests[i]; String dst = tests[i + 1]; String outExpected = tests[i + 2]; String outActual = UtilModel.getRelativePath(src, dst); assertEquals(outExpected, outActual); } }