diff --git a/pom.xml b/pom.xml index d38b3fc5f..356bd0f27 100644 --- a/pom.xml +++ b/pom.xml @@ -2,6 +2,7 @@ 4.0.0 + io.github.java-native jssc 2.9.7-SNAPSHOT @@ -55,6 +56,7 @@ 2.22.0 1.2.3 2.5.0 + 4.11.0 1.17 @@ -100,6 +102,18 @@ ${dependency.junit.version} test + + org.mockito + mockito-core + ${dependency.mockito.version} + test + + + org.mockito + mockito-inline + ${dependency.mockito.version} + test + diff --git a/src/main/java/jssc/SerialNativeInterface.java b/src/main/java/jssc/SerialNativeInterface.java index b0266014f..6172fced3 100644 --- a/src/main/java/jssc/SerialNativeInterface.java +++ b/src/main/java/jssc/SerialNativeInterface.java @@ -100,6 +100,25 @@ public class SerialNativeInterface { */ public static final String PROPERTY_JSSC_PARMRK = "JSSC_PARMRK"; + /** + * Allow set exotic port name(s) + * + * Usage: + * System.setProperty("JSSC_ALLOW_EXOTIC_NAMES", "true"); + * + * @since 2.9.7 + */ + public static final String PROPERTY_JSSC_ALLOW_EXOTIC_NAMES = "JSSC_ALLOW_EXOTIC_NAMES"; + /** + * Exotic port name(s) + * + * Usage: + * System.setProperty("JSSC_EXOTIC_NAMES", "ttyU,com"); + * + * @since 2.9.7 + */ + public static final String PROPERTY_JSSC_EXOTIC_NAMES = "JSSC_EXOTIC_NAMES"; + private static int osType; static { String osName = System.getProperty("os.name"); diff --git a/src/main/java/jssc/SerialPortList.java b/src/main/java/jssc/SerialPortList.java index 564938e3d..4f7f5e52d 100644 --- a/src/main/java/jssc/SerialPortList.java +++ b/src/main/java/jssc/SerialPortList.java @@ -36,8 +36,8 @@ public class SerialPortList { private static SerialNativeInterface serialInterface; - private static final Pattern PORTNAMES_REGEXP; - private static final String PORTNAMES_PATH; + private static Pattern PORTNAMES_REGEXP; + private static String PORTNAMES_PATH; /** * Default constructor @@ -47,9 +47,16 @@ private SerialPortList() {} static { serialInterface = new SerialNativeInterface(); + initSearchParameters(); + } + + /** + * For unit testing purposes + */ + public static void initSearchParameters() { switch (SerialNativeInterface.getOsType()) { case SerialNativeInterface.OS_LINUX: { - PORTNAMES_REGEXP = Pattern.compile("(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO|ttyM|ttyMXUSB|ttyMUE)[0-9]{1,3}"); + PORTNAMES_REGEXP = Pattern.compile("(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO|ttyM|ttyMXUSB|ttyMUE" + getExoticPortsNames() + ")[0-9]{1,3}"); PORTNAMES_PATH = "/dev/"; break; } @@ -59,7 +66,7 @@ private SerialPortList() {} break; } case SerialNativeInterface.OS_MAC_OS_X: { - PORTNAMES_REGEXP = Pattern.compile("(tty|cu)\\..*"); + PORTNAMES_REGEXP = Pattern.compile("(tty|cu" + getExoticPortsNames() + ")\\..*"); PORTNAMES_PATH = "/dev/"; break; } @@ -76,6 +83,36 @@ private SerialPortList() {} } } + /** + * For unit testing purposes + */ + public static Pattern getPortnamesRegexp() { + return PORTNAMES_REGEXP; + } + + private static String getExoticPortsNames() { + String result = ""; + String readExoticNamesValue = System.getProperty(SerialNativeInterface.PROPERTY_JSSC_ALLOW_EXOTIC_NAMES, "false"), + exoticPortNamesValue = System.getProperty(SerialNativeInterface.PROPERTY_JSSC_EXOTIC_NAMES, ""); + boolean decodeExoticNames = false; + + try { + decodeExoticNames = Boolean.parseBoolean(readExoticNamesValue) && !exoticPortNamesValue.isEmpty(); + } catch (Exception e) { + e.printStackTrace(); + } + + if(decodeExoticNames) { + String[] portsNamesCandidate = exoticPortNamesValue.split("[^a-zA-Z]"); + for(String singlePortName : portsNamesCandidate) { + if(!singlePortName.isEmpty()) { + result += "|" + singlePortName; + } + } + } + return result; + } + //since 2.1.0 -> Fully rewritten port name comparator private static final Comparator PORTNAMES_COMPARATOR = new Comparator() { diff --git a/src/test/java/jssc/SerialPortListTest.java b/src/test/java/jssc/SerialPortListTest.java new file mode 100644 index 000000000..a55ebc620 --- /dev/null +++ b/src/test/java/jssc/SerialPortListTest.java @@ -0,0 +1,95 @@ +package jssc; + +import jssc.junit.rules.DisplayMethodNameRule; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + + +public class SerialPortListTest extends DisplayMethodNameRule { + + private static final String BASIC_LINUX_PORTNAME_REGEXP = "(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO|ttyM|ttyMXUSB|ttyMUE%s)[0-9]{1,3}"; + private static final String BASIC_MAC_OS_PORTNAME_REGEXP = "(tty|cu%s)\\..*"; + + private void prepareEnv() { + System.clearProperty(SerialNativeInterface.PROPERTY_JSSC_ALLOW_EXOTIC_NAMES); + System.clearProperty(SerialNativeInterface.PROPERTY_JSSC_EXOTIC_NAMES); + } + + @Test + public void checkSerialPortNameRegExpOnLinux() { + MockedStatic serialNativeInterface = null; + prepareEnv(); + + try { + serialNativeInterface = Mockito.mockStatic(SerialNativeInterface.class); + serialNativeInterface.when(SerialNativeInterface::getOsType).thenReturn(SerialNativeInterface.OS_LINUX); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_LINUX_PORTNAME_REGEXP, ""), SerialPortList.getPortnamesRegexp().pattern()); + + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_EXOTIC_NAMES, "abc"); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_LINUX_PORTNAME_REGEXP, ""), SerialPortList.getPortnamesRegexp().pattern()); + + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_ALLOW_EXOTIC_NAMES, "true"); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_LINUX_PORTNAME_REGEXP, "|abc"), SerialPortList.getPortnamesRegexp().pattern()); + + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_ALLOW_EXOTIC_NAMES, "false"); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_LINUX_PORTNAME_REGEXP, ""), SerialPortList.getPortnamesRegexp().pattern()); + + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_ALLOW_EXOTIC_NAMES, "true"); + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_EXOTIC_NAMES, "abc1d|bvc"); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_LINUX_PORTNAME_REGEXP, "|abc|d|bvc"), SerialPortList.getPortnamesRegexp().pattern()); + + System.clearProperty(SerialNativeInterface.PROPERTY_JSSC_EXOTIC_NAMES); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_LINUX_PORTNAME_REGEXP, ""), SerialPortList.getPortnamesRegexp().pattern()); + } finally { + if(serialNativeInterface != null) { + serialNativeInterface.close(); + } + } + } + + @Test + public void checkSerialPortNameRegExpOnMacOS() { + MockedStatic serialNativeInterface = null; + prepareEnv(); + + try { + serialNativeInterface = Mockito.mockStatic(SerialNativeInterface.class); + serialNativeInterface.when(SerialNativeInterface::getOsType).thenReturn(SerialNativeInterface.OS_MAC_OS_X); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_MAC_OS_PORTNAME_REGEXP, ""), SerialPortList.getPortnamesRegexp().pattern()); + + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_EXOTIC_NAMES, "abc"); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_MAC_OS_PORTNAME_REGEXP, ""), SerialPortList.getPortnamesRegexp().pattern()); + + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_ALLOW_EXOTIC_NAMES, "true"); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_MAC_OS_PORTNAME_REGEXP, "|abc"), SerialPortList.getPortnamesRegexp().pattern()); + + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_ALLOW_EXOTIC_NAMES, "false"); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_MAC_OS_PORTNAME_REGEXP, ""), SerialPortList.getPortnamesRegexp().pattern()); + + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_ALLOW_EXOTIC_NAMES, "true"); + System.setProperty(SerialNativeInterface.PROPERTY_JSSC_EXOTIC_NAMES, "abc1d|bvc"); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_MAC_OS_PORTNAME_REGEXP, "|abc|d|bvc"), SerialPortList.getPortnamesRegexp().pattern()); + + System.clearProperty(SerialNativeInterface.PROPERTY_JSSC_EXOTIC_NAMES); + SerialPortList.initSearchParameters(); + Assert.assertEquals(String.format(BASIC_MAC_OS_PORTNAME_REGEXP, ""), SerialPortList.getPortnamesRegexp().pattern()); + } finally { + if(serialNativeInterface != null) { + serialNativeInterface.close(); + } + } + } +}