This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 41ce36f57713fb104c9e265878ddfda9074b86e0
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sun May 24 08:51:04 2026 -0400

    CAY-2949 CayenneModeler MCP: dbimport_run tool
    
    preliminary refactoring - node ID calculator needs to be shared
---
 .../cayenne/modeler/pref/PreferenceNodeIds.java    |   8 +-
 .../modeler/pref/PreferenceNodeIdsTest.java        | 123 +++++++++++++++++++++
 2 files changed, 126 insertions(+), 5 deletions(-)

diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PreferenceNodeIds.java
 
b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PreferenceNodeIds.java
similarity index 92%
rename from 
modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PreferenceNodeIds.java
rename to 
modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PreferenceNodeIds.java
index fef18c281..e8be4c3c5 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PreferenceNodeIds.java
+++ 
b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PreferenceNodeIds.java
@@ -25,12 +25,10 @@ import java.security.NoSuchAlgorithmException;
 import java.util.prefs.Preferences;
 
 /**
- * Encodes a file path into a single-segment {@link Preferences} node name. 
The id has
- * the form {@code <16-hex-sha256>-<sanitized-basename>} and stays under 
{@link #MAX_LEN}
- * characters, well below {@link Preferences#MAX_NAME_LENGTH}. The original 
absolute
- * path is meant to be stored alongside the node as a {@code path} value.
+ * Does repeatable encoding of a file path into a single-segment {@link 
Preferences} node name. The id has
+ * the form {@code <16-hex-sha256>-<sanitized-basename>} and stays under 
{@link Preferences#MAX_NAME_LENGTH}.
  */
-class PreferenceNodeIds {
+public class PreferenceNodeIds {
 
     static final int MAX_LEN = 60;
     static final int HASH_LEN = 16;
diff --git 
a/modeler/cayenne-modeler-prefs/src/test/java/org/apache/cayenne/modeler/pref/PreferenceNodeIdsTest.java
 
b/modeler/cayenne-modeler-prefs/src/test/java/org/apache/cayenne/modeler/pref/PreferenceNodeIdsTest.java
new file mode 100644
index 000000000..5b9c51ade
--- /dev/null
+++ 
b/modeler/cayenne-modeler-prefs/src/test/java/org/apache/cayenne/modeler/pref/PreferenceNodeIdsTest.java
@@ -0,0 +1,123 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.pref;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class PreferenceNodeIdsTest {
+
+    @Test
+    public void idForPathIsStable() {
+        String id1 = 
PreferenceNodeIds.idForPath("/home/user/project/myapp.xml");
+        String id2 = 
PreferenceNodeIds.idForPath("/home/user/project/myapp.xml");
+        assertEquals(id1, id2);
+    }
+
+    @Test
+    public void idForPathStaysUnderMaxLen() {
+        String longPath = 
"/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/very-long-name.xml";
+        String id = PreferenceNodeIds.idForPath(longPath);
+        assertTrue(id.length() <= PreferenceNodeIds.MAX_LEN,
+                "id length " + id.length() + " exceeds MAX_LEN " + 
PreferenceNodeIds.MAX_LEN);
+    }
+
+    @Test
+    public void idForPathStartsWithHash() {
+        String id = PreferenceNodeIds.idForPath("/foo/bar.xml");
+        assertEquals(PreferenceNodeIds.HASH_LEN, id.indexOf('-'),
+                "id should start with exactly HASH_LEN hex chars before the 
dash");
+    }
+
+    @Test
+    public void idForPathDifferentPathsProduceDifferentIds() {
+        String id1 = PreferenceNodeIds.idForPath("/project/a.xml");
+        String id2 = PreferenceNodeIds.idForPath("/project/b.xml");
+        assertTrue(!id1.equals(id2), "different paths must produce different 
ids");
+    }
+
+    @Test
+    public void idForPathXmlSuffixStripped() {
+        String withXml = PreferenceNodeIds.idForPath("/foo/bar.xml");
+        String withoutXml = PreferenceNodeIds.idForPath("/foo/bar");
+        assertEquals(withXml, withoutXml, ".xml suffix must be stripped before 
hashing");
+    }
+
+    @Test
+    public void idForPathNullReturnsHashOnly() {
+        String id = PreferenceNodeIds.idForPath(null);
+        assertEquals(PreferenceNodeIds.HASH_LEN, id.length());
+    }
+
+    @Test
+    public void canonicalizeNullReturnsEmpty() {
+        assertEquals("", PreferenceNodeIds.canonicalize(null));
+    }
+
+    @Test
+    public void canonicalizeStripsXmlSuffix() {
+        String result = PreferenceNodeIds.canonicalize("/foo/bar.xml");
+        assertTrue(result.endsWith("/foo/bar"), "expected .xml stripped, got: 
" + result);
+    }
+
+    @Test
+    public void canonicalizeConvertsBackslashes() {
+        String result = 
PreferenceNodeIds.canonicalize("C:\\Users\\test\\project.xml");
+        assertTrue(!result.contains("\\"), "backslashes must be converted to 
forward slashes");
+    }
+
+    @Test
+    public void basenameExtractsLastSegment() {
+        assertEquals("myproject", 
PreferenceNodeIds.basename("/home/user/myproject"));
+    }
+
+    @Test
+    public void basenameNoSlashReturnsInput() {
+        assertEquals("standalone", PreferenceNodeIds.basename("standalone"));
+    }
+
+    @Test
+    public void sanitizeAllowsAlphanumAndSafePunctuation() {
+        assertEquals("Abc-123_.", PreferenceNodeIds.sanitize("Abc-123_."));
+    }
+
+    @Test
+    public void sanitizeReplacesSpacesAndSpecialChars() {
+        String result = PreferenceNodeIds.sanitize("my project (v2)");
+        assertEquals("my_project__v2_", result);
+    }
+
+    @Test
+    public void sanitizeEmptyInputReturnsEmpty() {
+        assertEquals("", PreferenceNodeIds.sanitize(""));
+    }
+
+    @Test
+    public void sha256HexReturnsSixtyFourChars() {
+        assertEquals(64, PreferenceNodeIds.sha256Hex("hello").length());
+    }
+
+    @Test
+    public void sha256HexIsStable() {
+        assertEquals(PreferenceNodeIds.sha256Hex("test"), 
PreferenceNodeIds.sha256Hex("test"));
+    }
+}

Reply via email to