[util] Improve uniqueness in UniqueNameBuilder

Previously, it sometimes yielded non-unique short paths
even when the original paths were unique.

GitOrigin-RevId: 6104e7436e53c5fe1f3a862bf480409accadfa6b
This commit is contained in:
Sergej Jaskiewicz
2025-02-06 17:19:27 +01:00
committed by intellij-monorepo-bot
parent ee7ffb6c59
commit d1cc239f5f
2 changed files with 68 additions and 19 deletions

View File

@@ -11,13 +11,15 @@ public class UniqueNameBuilderTest extends TestCase {
builder.addPath("A", "/Users/yole/idea/foo/bar.java");
builder.addPath("B", "/Users/yole/idea/baz/bar.java");
assertEquals("foo/bar.java", builder.getShortPath("A"));
assertEquals("baz/bar.java", builder.getShortPath("B"));
}
public void testTwoLevel() {
UniqueNameBuilder<String> builder = new UniqueNameBuilder<>("", "/");
builder.addPath("A", "/Users/yole/idea/foo/buy/index.html");
builder.addPath("B", "/Users/yole/idea/bar/buy/index.html");
assertEquals("foo/\u2026/index.html", builder.getShortPath("A"));
assertEquals("foo//index.html", builder.getShortPath("A"));
assertEquals("bar/…/index.html", builder.getShortPath("B"));
}
public void testThreeLevel() {
@@ -29,43 +31,43 @@ public class UniqueNameBuilderTest extends TestCase {
builder.addPath("B2", "/Users/yole/idea/bar/after/somedir/index.html");
builder.addPath("B3", "/Users/yole/fabrique/bar/after/somedir/index.html");
assertEquals("idea/foo/before/\u2026/index.html", builder.getShortPath("A"));
assertEquals("idea/foo/before//index.html", builder.getShortPath("A"));
assertEquals("idea/foo/after/\u2026/index.html", builder.getShortPath("A2"));
assertEquals("fabrique/foo/before/\u2026/index.html", builder.getShortPath("A3"));
assertEquals("idea/foo/after//index.html", builder.getShortPath("A2"));
assertEquals("fabrique/foo/before//index.html", builder.getShortPath("A3"));
assertEquals("idea/bar/before/\u2026/index.html", builder.getShortPath("B"));
assertEquals("idea/bar/after/\u2026/index.html", builder.getShortPath("B2"));
assertEquals("fabrique/bar/after/\u2026/index.html", builder.getShortPath("B3"));
assertEquals("idea/bar/before//index.html", builder.getShortPath("B"));
assertEquals("idea/bar/after//index.html", builder.getShortPath("B2"));
assertEquals("fabrique/bar/after//index.html", builder.getShortPath("B3"));
}
public void testSeparator() {
UniqueNameBuilder<String> builder = new UniqueNameBuilder<>("", "\\");
builder.addPath("A", "/Users/yole/idea/foo/buy/index.html");
builder.addPath("B", "/Users/yole/idea/bar/buy/index.html");
assertEquals("foo\\\u2026\\index.html", builder.getShortPath("A"));
assertEquals("foo\\\\index.html", builder.getShortPath("A"));
}
public void testRoot() {
UniqueNameBuilder<String> builder = new UniqueNameBuilder<>("/Users/yole/idea", "/");
builder.addPath("A", "/Users/yole/idea/build/scripts/layouts.gant");
builder.addPath("B", "/Users/yole/idea/community/build/scripts/layouts.gant");
assertEquals("build/\u2026/layouts.gant", builder.getShortPath("A"));
assertEquals("community/\u2026/layouts.gant", builder.getShortPath("B"));
assertEquals("build//layouts.gant", builder.getShortPath("A"));
assertEquals("community//layouts.gant", builder.getShortPath("B"));
builder = new UniqueNameBuilder<>("", "/");
builder.addPath("A", "build/scripts/layouts.gant");
builder.addPath("B", "community/build/scripts/layouts.gant");
assertEquals("build/\u2026/layouts.gant", builder.getShortPath("A"));
assertEquals("community/\u2026/layouts.gant", builder.getShortPath("B"));
assertEquals("build//layouts.gant", builder.getShortPath("A"));
assertEquals("community//layouts.gant", builder.getShortPath("B"));
}
public void testShortenNames() {
UniqueNameBuilder<String> builder = new UniqueNameBuilder<>("/Users/yole/idea", "/");
builder.addPath("A", "/Users/yole/idea/build/scripts/layouts.gant");
builder.addPath("B", "/Users/yole/idea/community/build/scripts/layouts.gant");
assertEquals("build/\u2026/layouts.gant", builder.getShortPath("A"));
assertEquals("community/\u2026/layouts.gant", builder.getShortPath("B"));
assertEquals("build//layouts.gant", builder.getShortPath("A"));
assertEquals("community//layouts.gant", builder.getShortPath("B"));
}
public void testShortenNamesUnique() {
@@ -82,8 +84,36 @@ public class UniqueNameBuilderTest extends TestCase {
UniqueNameBuilder<String> builder = new UniqueNameBuilder<>("/Users/yole/idea", "/");
builder.addPath("A", "source/components/views/something/tmpl/default.php");
builder.addPath("B", "source/components/views/something_else/tmpl/default.php");
assertEquals("something/\u2026/default.php", builder.getShortPath("A"));
assertEquals("something_else/\u2026/default.php", builder.getShortPath("B"));
assertEquals("something//default.php", builder.getShortPath("A"));
assertEquals("something_else//default.php", builder.getShortPath("B"));
}
public void testShortenNamesUnique3() {
UniqueNameBuilder<String> builder = new UniqueNameBuilder<>("/js/js.tests/build/node", "/");
builder.addPath("A", "/js/js.tests/build/node/out-per-module/codegen/firBox/specialBuiltins/throwableImpl_v5.js");
builder.addPath("B", "/js/js.tests/build/node/out-per-module/codegen/firEs6Box/specialBuiltins/throwableImpl_v5.js");
builder.addPath("C", "/js/js.tests/build/node/out-per-module-min/codegen/firEs6Box/specialBuiltins/throwableImpl_v5.js");
builder.addPath("D", "/js/js.tests/build/node/out-per-module-min/codegen/firBox/specialBuiltins/throwableImpl_v5.js");
assertEquals("out-per-module/…/firBox/…/throwableImpl_v5.js", builder.getShortPath("A"));
assertEquals("out-per-module/…/firEs6Box/…/throwableImpl_v5.js", builder.getShortPath("B"));
assertEquals("out-per-module-min/…/firEs6Box/…/throwableImpl_v5.js", builder.getShortPath("C"));
assertEquals("out-per-module-min/…/firBox/…/throwableImpl_v5.js", builder.getShortPath("D"));
}
public void testShortenNamesUnique4() {
UniqueNameBuilder<String> builder = new UniqueNameBuilder<>("", "/");
builder.addPath("A", "foo1/bar/baar/baz1/qux/quux1/quuux/index.html");
builder.addPath("B", "foo2/bar/baar/baz2/qux/quux2/quuux/index.html");
builder.addPath("C", "foo2/bar/baar/baz1/qux/quux1/quuux/index.html");
builder.addPath("D", "foo2/bar/baz2/qux/quux2/quuux/index.html");
builder.addPath("E", "foo1/bar/qux/quux1/quuux/index.html");
builder.addPath("F", "foo2/qux/quux2/quuux/index.html");
assertEquals("foo1/…/baz1/…/quux1/…/index.html", builder.getShortPath("A"));
assertEquals("baar/baz2/…/quux2/…/index.html", builder.getShortPath("B"));
assertEquals("foo2/…/baz1/…/quux1/…/index.html", builder.getShortPath("C"));
assertEquals("bar/baz2/…/quux2/…/index.html", builder.getShortPath("D"));
assertEquals("foo1/bar/…/quux1/…/index.html", builder.getShortPath("E"));
assertEquals("foo2/…/quux2/…/index.html", builder.getShortPath("F"));
}
public void testFilesWithoutExtensions() {

View File

@@ -44,6 +44,21 @@ public final class UniqueNameBuilder<T> {
if (node == null) myChildren.put(word, node = new Node(word, this));
return node;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
render(builder, 0);
return builder.toString();
}
private void render(StringBuilder builder, int depth) {
for (int i = 0; i < depth; i++) builder.append(" ");
builder.append(myText.isEmpty() ? "[Root]" : myText).append("\n");
for (Node child : myChildren.values()) {
child.render(builder, depth + 1);
}
}
}
private final Node myRootNode = new Node("", null);
@@ -104,12 +119,15 @@ public final class UniqueNameBuilder<T> {
}
boolean skipFirstSeparator = true;
for (Node c = firstNodeBeforeNodeWithBranches; c != myRootNode; c = c.myParentNode) {
for (Node c = firstNodeBeforeNodeWithBranches; c != myRootNode;) {
if (c != fileNameNode && c != firstNodeBeforeNodeWithBranches && c.myParentNode.myChildren.size() == 1) {
b.append(mySeparator);
b.append("\u2026");
b.append("");
while (c.myParentNode != fileNameNode && c.myParentNode.myChildren.size() == 1) c = c.myParentNode;
do {
c = c.myParentNode;
}
while (c != fileNameNode && c.myParentNode.myChildren.size() == 1); // Don't print two or more ellipses in a row.
}
else {
if (c.myText.startsWith(VFS_SEPARATOR)) {
@@ -120,6 +138,7 @@ public final class UniqueNameBuilder<T> {
else {
b.append(c.myText);
}
c = c.myParentNode;
}
}
return b.toString();