diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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 + + http://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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..59f02e8 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ + +# uid.tools + +pom.xml: + +1. in repositories section: + + + ua.net.uid.releases + https://git.uid.net.ua/maven/releases/ + + +2. in dependencies section: + + + ua.net.uid + uid.tools + 1.0.0 + diff --git a/nb-configuration.xml b/nb-configuration.xml new file mode 100644 index 0000000..9910669 --- /dev/null +++ b/nb-configuration.xml @@ -0,0 +1,19 @@ + + + + + + apache20 + JDK_1.8 + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6279da6 --- /dev/null +++ b/pom.xml @@ -0,0 +1,103 @@ + + + 4.0.0 + ua.net.uid + uid.tools + 1.0.0-SNAPSHOT + jar + + + + ASL + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + org.junit.jupiter + junit-jupiter-engine + 5.5.1 + test + + + + com.h2database + h2 + [1.4.193, 1.5.0) + test + + + + + + + . + + LICENSE + NOTICE.txt + RELEASE.txt + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + true + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + maven-failsafe-plugin + 2.22.2 + + + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + true + @{project.version} + release + + + + + + + UTF-8 + 1.8 + 1.8 + + + + scm:git:https://git.uid.net.ua/git/uid/uid.tools.git + scm:git:https://git.uid.net.ua/git/uid/uid.tools.git + https://git.uid.net.ua/git/uid/uid.tools.git + HEAD + + + + + uid-releases + Release repository + https://git.uid.net.ua/maven/releases/ + + + uid-snapshots + Snapshots repository + https://git.uid.net.ua/maven/snapshots/ + + + \ No newline at end of file diff --git a/src/main/java/ua/net/uid/utils/Function.java b/src/main/java/ua/net/uid/utils/Function.java new file mode 100644 index 0000000..804999c --- /dev/null +++ b/src/main/java/ua/net/uid/utils/Function.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils; + +/** + * + * @author nightfall + * @param + * @param + */ +@FunctionalInterface +public interface Function { + R call(T param) throws Exception; +} diff --git a/src/main/java/ua/net/uid/utils/Getter.java b/src/main/java/ua/net/uid/utils/Getter.java new file mode 100644 index 0000000..af3d800 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/Getter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils; + +/** + * + * @author nightfall + * @param argument type + * @param result type + */ +public interface Getter { + V get(K key); +} diff --git a/src/main/java/ua/net/uid/utils/Procedure.java b/src/main/java/ua/net/uid/utils/Procedure.java new file mode 100644 index 0000000..4752c9e --- /dev/null +++ b/src/main/java/ua/net/uid/utils/Procedure.java @@ -0,0 +1,26 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils; + +/** + * + * @author nightfall + * @param argument type + */ +@FunctionalInterface +public interface Procedure { + void call(T param) throws Exception; +} diff --git a/src/main/java/ua/net/uid/utils/Setter.java b/src/main/java/ua/net/uid/utils/Setter.java new file mode 100644 index 0000000..a426d3f --- /dev/null +++ b/src/main/java/ua/net/uid/utils/Setter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils; + +/** + * + * @author nightfall + * @param + * @param + */ +public interface Setter { + void set(K name, V value); +} diff --git a/src/main/java/ua/net/uid/utils/concurrent/ReadyFuture.java b/src/main/java/ua/net/uid/utils/concurrent/ReadyFuture.java new file mode 100644 index 0000000..e3b3878 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/concurrent/ReadyFuture.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.concurrent; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +public final class ReadyFuture implements Future { + private final V result; + + public ReadyFuture(V result) { + this.result = result; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return true; + } + + @Override + public V get() { + return result; + } + + @Override + public V get(long timeout, TimeUnit unit) { + return result; + } +} diff --git a/src/main/java/ua/net/uid/utils/helpers/ArrayHelper.java b/src/main/java/ua/net/uid/utils/helpers/ArrayHelper.java new file mode 100644 index 0000000..6f87c7b --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/ArrayHelper.java @@ -0,0 +1,81 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +public class ArrayHelper { + private ArrayHelper() { + } + + public static int indexOf(final T[] array, final T item) { + return indexOf(array, item, 0); + } + + public static int indexOf(final T[] array, final T item, int from) { + if (array == null) return -1; + if (from < 0) from = 0; + final int length = array.length; + if (from >= length) return -1; + if (item == null) { + for (int i = from; i < length; ++i) { + if (array[i] == null) return i; + } + } else { + for (int i = from; i < length; ++i) { + if (item.equals(array[i])) return i; + } + } + return -1; + } + + public static int lastIndexOf(final T[] array, final T item) { + return lastIndexOf(array, item, Integer.MAX_VALUE); + } + + public static int lastIndexOf(final T[] array, final T item, int from) { + if (array == null || from < 0) return -1; + if (from >= array.length) from = array.length - 1; + if (item == null) { + for (int i = from; i >= 0; --i) { + if (array[i] == null) return i; + } + } else { + for (int i = from; i >= 0; --i) { + if (item.equals(array[i])) return i; + } + } + return -1; + } + + /* + !!! not compiled in java 9 + @SuppressWarnings("unchecked") + public static T[] toArray(Collection collection) { + return (T[]) collection.toArray(); + } + + public static T[] toSortedArray(Collection collection) { + final T[] result = toArray(collection); + Arrays.sort(result); + return result; + } + + public static T[] toSortedArray(Collection collection, Comparator comparator) { + final T[] result = toArray(collection); + Arrays.sort(result, comparator); + return result; + } + */ +} diff --git a/src/main/java/ua/net/uid/utils/helpers/Cast.java b/src/main/java/ua/net/uid/utils/helpers/Cast.java new file mode 100644 index 0000000..f646a9e --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/Cast.java @@ -0,0 +1,142 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Cast { + private static final Pattern REGEXP_BOOLEAN = Pattern.compile("^\\s*(false|f|no|off|n|0+|-)|(true|t|yes|on|y|\\d+|\\+)\\s*$", Pattern.CASE_INSENSITIVE); + private static final Pattern REGEXP_EMAIL = Pattern.compile("^\\s*([-a-z0-9~!$%^&*_=+}{'?]+(\\.[-a-z0-9~!$%^&*_=+}{'?]+)*@([a-z0-9_][-a-z0-9_]*(\\.[-a-z0-9_]+)*))\\s*$", Pattern.CASE_INSENSITIVE); + + private Cast() { + } + + public static Boolean toBoolean(final String text, Boolean defaults) { + if (text != null) { + Matcher matcher = REGEXP_BOOLEAN.matcher(text); + if (matcher.matches()) return matcher.group(2) != null; + } + return defaults; + } + + public static Byte toByte(final String value, final Byte defaults) { + if (value != null) { + try { + return Byte.decode(value); + } catch (NumberFormatException ignored) { + } + } + return defaults; + } + + public static Short toShort(final String value, final Short defaults) { + if (value != null) { + try { + return Short.decode(value); + } catch (NumberFormatException ignored) { + } + } + return defaults; + } + + public static Integer toInteger(final String value, final Integer defaults) { + if (value != null) { + try { + return Integer.decode(value); + } catch (NumberFormatException ignored) { + } + } + return defaults; + } + + public static Long toLong(final String value, final Long defaults) { + if (value != null) { + try { + return Long.decode(value); + } catch (NumberFormatException ignored) { + } + } + return defaults; + } + + public static Float toFloat(final String value, final Float defaults) { + if (value != null) { + try { + return Float.parseFloat(value); + } catch (NumberFormatException ignored) { + } + } + return defaults; + } + + public static Double toDouble(final String value, final Double defaults) { + if (value != null) { + try { + return Double.parseDouble(value); + } catch (NumberFormatException ignored) { + } + } + return defaults; + } + + public static BigInteger toBigInteger(String value, BigInteger defaults) { + if (value != null) { + try { + return new BigInteger(value); + } catch (NumberFormatException ignored) { + } + } + return defaults; + } + + public static BigDecimal toBigDecimal(String value, BigDecimal defaults) { + if (value != null) { + try { + return new BigDecimal(value); + } catch (NumberFormatException ignored) { + } + } + return defaults; + } + + public static String toEmail(String value, final String defaults) { + if (value != null) { + Matcher matcher = REGEXP_EMAIL.matcher(value); + if (matcher.matches()) return matcher.group(1); + } + return defaults; + } + + public static Date toDate(DateFormat format, String value, Date defValue) { + if (value != null) { + try { + return format.parse(value); + } catch (ParseException ignored) { + } + } + return defValue; + } + + public static > T toEnum(Class enumType, String value, T defaults) { + return EnumHelper.valueOf(enumType, value, defaults); + } +} diff --git a/src/main/java/ua/net/uid/utils/helpers/CommonHelper.java b/src/main/java/ua/net/uid/utils/helpers/CommonHelper.java new file mode 100644 index 0000000..4ca0bd6 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/CommonHelper.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class CommonHelper { + private CommonHelper() { + } + + public static void close(AutoCloseable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (final Exception ignored) { + } + } + } + + public static boolean isEmpty(CharSequence chars) { + return chars == null || chars.length() == 0; + } + + public static boolean isEmpty(String string) { + return string == null || string.isEmpty(); + } + + public static boolean isEmpty(Collection collection) { + return collection == null || collection.isEmpty(); + } + + public static boolean isEmpty(Map map) { + return map == null || map.isEmpty(); + } + + public static boolean isEmpty(T[] array) { + return array == null || array.length == 0; + } + + public static Set setOf(T ... items) { + Set result = new HashSet<>(); + if (!isEmpty(items)) + Collections.addAll(result, items); + return result; + } +} diff --git a/src/main/java/ua/net/uid/utils/helpers/EnumHelper.java b/src/main/java/ua/net/uid/utils/helpers/EnumHelper.java new file mode 100644 index 0000000..2735fd1 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/EnumHelper.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class EnumHelper { + private EnumHelper() { + } + + public static > T valueOf(Class enumType, String value, T defValue) { + if (value == null) return defValue; + try { + return Enum.valueOf(enumType, value); + } catch (IllegalArgumentException ex) { + return defValue; + } + } + + public static > T valueOf(Class enumType, String value) { + return valueOf(enumType, value, null); + } + + public static > List toList(final Class enumType) { + return Arrays.asList(enumType.getEnumConstants()); + } + + public static > Map toMap(final Class enumType) { + Map map = new LinkedHashMap<>(); + for (T e : enumType.getEnumConstants()) + map.put(e.name(), e); + return map; + } +} diff --git a/src/main/java/ua/net/uid/utils/helpers/NumberHelper.java b/src/main/java/ua/net/uid/utils/helpers/NumberHelper.java new file mode 100644 index 0000000..e8224aa --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/NumberHelper.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +public class NumberHelper { + + private NumberHelper() { + } + + public static byte[] longToBytes(long l) { + byte[] result = new byte[8]; + for (int i = 7; i >= 0; --i) { + result[i] = (byte) (l & 0xff); + l >>= 8; + } + return result; + } + + public static long bytesToLong(byte[] b) { + long result = 0; + for (int i = 0; i < 8; i++) { + result <<= 8; + result |= (b[i] & 0xFF); + } + return result; + } + + + /*public static Number parse(CharSequence source, ParsePosition position) { + int offset = StringHelper.skipWhitespace(source, position.getIndex()); + if (offset < source.length()) { + + } + position.setErrorIndex(offset); + return null; + }*/ +} diff --git a/src/main/java/ua/net/uid/utils/helpers/RandomHelper.java b/src/main/java/ua/net/uid/utils/helpers/RandomHelper.java new file mode 100644 index 0000000..4c2c64b --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/RandomHelper.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +public class RandomHelper { + public static char[] randomChars(int minLength, int maxLength) { + return randomChars(minLength, maxLength, ThreadLocalRandom.current()); + } + + public static char[] randomChars(int minLength, int maxLength, Random random) { + assert minLength <= maxLength; + int length = minLength == maxLength ? minLength : minLength + random.nextInt(maxLength - minLength); + char[] text = new char[length]; + for (int i = 0; i < length; ++i) { + text[i] = (char) (random.nextInt(126 - 32) + 32); + } + return text; + } + + public static String randomString(int minLength, int maxLength) { + return new String(randomChars(minLength, maxLength)); + } + + public static String randomString(int minLength, int maxLength, Random random) { + return new String(randomChars(minLength, maxLength, random)); + } +} diff --git a/src/main/java/ua/net/uid/utils/helpers/RegexHelper.java b/src/main/java/ua/net/uid/utils/helpers/RegexHelper.java new file mode 100644 index 0000000..67071b9 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/RegexHelper.java @@ -0,0 +1,66 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class RegexHelper { + private static final Pattern NAMED_GROUP = Pattern.compile("(?:[^\\\\]+|(?:\\\\.)+)?\\(\\?<([a-z][a-z0-9]*)>"); + + private RegexHelper() { + } + + + public static Set getNamedGroupsSet(Pattern pattern) { + HashSet result = new HashSet<>(); + Matcher matcher = NAMED_GROUP.matcher(pattern.pattern()); + while (matcher.find()) { + result.add(matcher.group(1)); + } + return result; + } + + public static Map getNamedGroups(Pattern pattern) { + /* + !!! does not work in java 9 + try { + Method method = Pattern.class.getDeclaredMethod("namedGroups"); + method.setAccessible(true); + @SuppressWarnings("unchecked") + Map groups = (Map) method.invoke(pattern); + return Collections.unmodifiableMap(groups); + } catch (ReflectiveOperationException ex) { + throw new RuntimeException(ex); + } + */ + throw new UnsupportedOperationException("does not work in java 9"); + } + + public static Map getGroupsByName(Matcher matcher, Set groups) { + if (groups != null) { + HashMap map = new HashMap<>(); + for (String group : groups) + map.put(group, matcher.group(group)); + return map; + } + return null; + } +} diff --git a/src/main/java/ua/net/uid/utils/helpers/StringHelper.java b/src/main/java/ua/net/uid/utils/helpers/StringHelper.java new file mode 100644 index 0000000..c767bee --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/StringHelper.java @@ -0,0 +1,202 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +import java.io.IOException; + +public class StringHelper { + private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + private StringHelper() { + } + + public static char[] toHex(byte[] bytes) { + final char[] buffer = new char[bytes.length * 2]; + for (int i = 0, n = 0; i < bytes.length; ++i) { + final int val = bytes[i] & 255; + buffer[n++] = HEX_CHARS[val >>> 4]; + buffer[n++] = HEX_CHARS[val & 15]; + } + return buffer; + } + + public static void toHex(final Appendable builder, byte[] bytes) throws IOException { + for (byte b : bytes) { + final int val = b & 255; + builder.append(HEX_CHARS[val >>> 4]); + builder.append(HEX_CHARS[val & 15]); + } + } + + public static void escape(final Appendable builder, final CharSequence string, int start, int end) throws IOException { + for (int e = start; e < end; ++e) { + char chr = string.charAt(e); + switch (chr) { + case '"': + case '\\': + break; + case '\t': + chr = 't'; + break; + case '\b': + chr = 'b'; + break; + case '\n': + chr = 'n'; + break; + case '\r': + chr = 'r'; + break; + case '\f': + chr = 'f'; + break; + default: + if (chr < 32) { + if (start < e) builder.append(string, start, e); + builder.append("\\u"); + for (int i = 12; i >= 0; i -= 4) + builder.append(HEX_CHARS[(chr >> i) & 15]); + start = e + 1; + } + continue; + } + if (start < e) builder.append(string, start, e); + start = e + 1; + builder.append('\\').append(chr); + } + if (start < end) builder.append(string, start, end); + } + + public static void escape(final Appendable builder, final CharSequence string) throws IOException { + escape(builder, string, 0, string.length()); + } + + public static String escape(final CharSequence string) { + final StringBuilder builder = new StringBuilder(string.length() * 2); + try { + escape(builder, string); + } catch (IOException ignored) { + } + return builder.toString(); + } + + public static void unescape(final Appendable builder, final CharSequence string) throws IOException { + final int length = string.length(); + int start = 0; + for (int end = 0; end < length; ++end) { + char chr = string.charAt(end); + if (chr == '\\') { + if (start < end) builder.append(string, start, end); + chr = string.charAt(++end); + switch (chr) { + case '"': + case '\\': + break; + case 't': + chr = '\t'; + break; + case 'b': + chr = '\b'; + break; + case 'n': + chr = '\n'; + break; + case 'r': + chr = '\r'; + break; + case 'f': + chr = '\f'; + break; + case 'u': + chr = 0; + for (int i = 1; i <= 4; ++i) { + final char tmp = string.charAt(end + i); + chr <<= 4; + if (tmp >= '0' && tmp <= '9') { + chr += tmp - '0'; + } else if (tmp >= 'A' && tmp <= 'F') { + chr += tmp - ('A' - 10); + } else if (tmp >= 'a' && tmp <= 'f') { + chr += tmp - ('a' - 10); + } else { + throw new NumberFormatException(string.subSequence(end - 1, end + 5).toString()); + } + } + end += 4; + break; + default: + continue; + } + builder.append(chr); + start = end + 1; + } + } + if (start < length) builder.append(string, start, length); + } + + public static String unescape(final CharSequence string) { + final StringBuilder builder = new StringBuilder(string.length()); + try { + unescape(builder, string); + } catch (IOException ignored) { + } + return builder.toString(); + } + + public static String trim(String string) { + return string == null ? null : string.trim(); + } + + @SuppressWarnings("SpellCheckingInspection") + public static String ltrim(String string) { + if (string == null) return null; + int i = 0, length = string.length(); + while (i < length && Character.isWhitespace(string.charAt(i))) + ++i; + return i == 0 ? string : (i < length ? string.substring(i) : ""); + } + + @SuppressWarnings("SpellCheckingInspection") + public static String rtrim(String string) { + if (string == null) return null; + int i = string.length(); + while (i >= 0 && Character.isWhitespace(string.charAt(i - 1))) + --i; + return i <= 0 ? "" : string.substring(0, i); + } + + public static int skipWhitespace(CharSequence source, int offset) { + while (offset < source.length() && Character.isWhitespace(source.charAt(offset))) + ++offset; + return offset; + } + + public static boolean isAscii(int chr) { + return ((chr & 0xFFFFFF80) == 0); + } + + public static boolean isAsciiUpper(int chr) { + return chr >= 'A' && chr <= 'Z'; + } + + public static boolean isAsciiLower(int chr) { + return chr >= 'a' && chr <= 'z'; + } + + public static boolean isAsciiDigit(int chr) { + return chr >= '0' && chr <= '9'; + } +} diff --git a/src/main/java/ua/net/uid/utils/helpers/Transliterate.java b/src/main/java/ua/net/uid/utils/helpers/Transliterate.java new file mode 100644 index 0000000..ad8447d --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/Transliterate.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +import java.text.Normalizer; +import java.util.Arrays; +import java.util.regex.Pattern; + +public class Transliterate { + private static final Pattern SYMBOLS = Pattern.compile("[^\\p{L}\\p{Nd}]+"); + private static final char[][] CHARS = { + // Latin + {'À', 'A'}, {'Á', 'A'}, {'Â', 'A'}, {'Ã', 'A'}, {'Ä', 'A'}, {'Å', 'A'}, {'Æ', 'A', 'E'}, {'Ç', 'C'}, {'È', 'E'}, {'É', 'E'}, {'Ê', 'E'}, {'Ë', 'E'}, + {'Ì', 'I'}, {'Í', 'I'}, {'Î', 'I'}, {'Ï', 'I'}, {'Ð', 'D'}, {'Ñ', 'N'}, {'Ò', 'O'}, {'Ó', 'O'}, {'Ô', 'O'}, {'Õ', 'O'}, {'Ö', 'O'}, {'Ő', 'O'}, + {'Ø', 'O'}, {'Ù', 'U'}, {'Ú', 'U'}, {'Û', 'U'}, {'Ü', 'U'}, {'Ű', 'U'}, {'Ý', 'Y'}, {'Þ', 'T', 'H'}, {'ß', 's', 's'}, + {'à', 'a'}, {'á', 'a'}, {'â', 'a'}, {'ã', 'a'}, {'ä', 'a'}, {'å', 'a'}, {'æ', 'a', 'e'}, {'ç', 'c'}, {'è', 'e'}, {'é', 'e'}, {'ê', 'e'}, {'ë', 'e'}, + {'ì', 'i'}, {'í', 'i'}, {'î', 'i'}, {'ï', 'i'}, {'ð', 'd'}, {'ñ', 'n'}, {'ò', 'o'}, {'ó', 'o'}, {'ô', 'o'}, {'õ', 'o'}, {'ö', 'o'}, {'ő', 'o'}, + {'ø', 'o'}, {'ù', 'u'}, {'ú', 'u'}, {'û', 'u'}, {'ü', 'u'}, {'ű', 'u'}, {'ý', 'y'}, {'þ', 't', 'h'}, {'ÿ', 'y'}, + //Latin symbols + {'©', '(', 'c', ')'}, + //Greek + {'Α', 'A'}, {'Β', 'B'}, {'Γ', 'G'}, {'Δ', 'D'}, {'Ε', 'E'}, {'Ζ', 'Z'}, {'Η', 'H'}, {'Θ', '8'}, {'Ι', 'I'}, {'Κ', 'K'}, {'Λ', 'L'}, {'Μ', 'M'}, + {'Ν', 'N'}, {'Ξ', '3'}, {'Ο', 'O'}, {'Π', 'P'}, {'Ρ', 'R'}, {'Σ', 'S'}, {'Τ', 'T'}, {'Υ', 'Y'}, {'Φ', 'F'}, {'Χ', 'X'}, {'Ψ', 'P', 'S'}, {'Ω', 'W'}, + {'Ά', 'A'}, {'Έ', 'E'}, {'Ί', 'I'}, {'Ό', 'O'}, {'Ύ', 'Y'}, {'Ή', 'H'}, {'Ώ', 'W'}, {'Ϊ', 'I'}, {'Ϋ', 'Y'}, + {'α', 'a'}, {'β', 'b'}, {'γ', 'g'}, {'δ', 'd'}, {'ε', 'e'}, {'ζ', 'z'}, {'η', 'h'}, {'θ', '8'}, {'ι', 'i'}, {'κ', 'k'}, {'λ', 'l'}, {'μ', 'm'}, + {'ν', 'n'}, {'ξ', '3'}, {'ο', 'o'}, {'π', 'p'}, {'ρ', 'r'}, {'σ', 's'}, {'τ', 't'}, {'υ', 'y'}, {'φ', 'f'}, {'χ', 'x'}, {'ψ', 'p', 's'}, {'ω', 'w'}, + {'ά', 'a'}, {'έ', 'e'}, {'ί', 'i'}, {'ό', 'o'}, {'ύ', 'y'}, {'ή', 'h'}, {'ώ', 'w'}, {'ς', 's'}, {'ϊ', 'i'}, {'ΰ', 'y'}, {'ϋ', 'y'}, {'ΐ', 'i'}, + //Turkish + {'Ş', 'S'}, {'İ', 'I'}, {'Ç', 'C'}, {'Ü', 'U'}, {'Ö', 'O'}, {'Ğ', 'G'}, {'ş', 's'}, {'ı', 'i'}, {'ç', 'c'}, {'ü', 'u'}, {'ö', 'o'}, {'ğ', 'g'}, + //Russian + {'А', 'A'}, {'Б', 'B'}, {'В', 'V'}, {'Г', 'G'}, {'Д', 'D'}, {'Е', 'E'}, {'Ё', 'Y', 'o'}, {'Ж', 'Z', 'h'}, {'З', 'Z'}, {'И', 'I'}, {'Й', 'J'}, {'К', 'K'}, + {'Л', 'L'}, {'М', 'M'}, {'Н', 'N'}, {'О', 'O'}, {'П', 'P'}, {'Р', 'R'}, {'С', 'S'}, {'Т', 'T'}, {'У', 'U'}, {'Ф', 'F'}, {'Х', 'H'}, {'Ц', 'C'}, + {'Ч', 'C', 'h'}, {'Ш', 'S', 'h'}, {'Щ', 'S', 'h'}, {'Ъ'}, {'Ы', 'Y'}, {'Ь'}, {'Э', 'E'}, {'Ю', 'Y', 'u'}, {'Я', 'Y', 'a'}, + {'а', 'a'}, {'б', 'b'}, {'в', 'v'}, {'г', 'g'}, {'д', 'd'}, {'е', 'e'}, {'ё', 'y', 'o'}, {'ж', 'z', 'h'}, {'з', 'z'}, {'и', 'i'}, {'й', 'j'}, {'к', 'k'}, + {'л', 'l'}, {'м', 'm'}, {'н', 'n'}, {'о', 'o'}, {'п', 'p'}, {'р', 'r'}, {'с', 's'}, {'т', 't'}, {'у', 'u'}, {'ф', 'f'}, {'х', 'h'}, {'ц', 'c'}, + {'ч', 'c', 'h'}, {'ш', 's', 'h'}, {'щ', 's', 'h'}, {'ъ'}, {'ы', 'y'}, {'ь'}, {'э', 'e'}, {'ю', 'y', 'u'}, {'я', 'y', 'a'}, + //Ukrainian + {'Є', 'Y', 'e'}, {'І', 'I'}, {'Ї', 'Y', 'i'}, {'Ґ', 'G'}, {'є', 'y', 'e'}, {'і', 'i'}, {'ї', 'y', 'i'}, {'ґ', 'g'}, + //Czech + {'Č', 'C'}, {'Ď', 'D'}, {'Ě', 'E'}, {'Ň', 'N'}, {'Ř', 'R'}, {'Š', 'S'}, {'Ť', 'T'}, {'Ů', 'U'}, {'Ž', 'Z'}, + {'č', 'c'}, {'ď', 'd'}, {'ě', 'e'}, {'ň', 'n'}, {'ř', 'r'}, {'š', 's'}, {'ť', 't'}, {'ů', 'u'}, {'ž', 'z'}, + //Polish + {'Ą', 'A'}, {'Ć', 'C'}, {'Ę', 'e'}, {'Ł', 'L'}, {'Ń', 'N'}, {'Ó', 'o'}, {'Ś', 'S'}, {'Ź', 'Z'}, {'Ż', 'Z'}, + {'ą', 'a'}, {'ć', 'c'}, {'ę', 'e'}, {'ł', 'l'}, {'ń', 'n'}, {'ó', 'o'}, {'ś', 's'}, {'ź', 'z'}, {'ż', 'z'}, + //Latvian + {'Ā', 'A'}, {'Č', 'C'}, {'Ē', 'E'}, {'Ģ', 'G'}, {'Ī', 'i'}, {'Ķ', 'k'}, {'Ļ', 'L'}, {'Ņ', 'N'}, {'Š', 'S'}, {'Ū', 'u'}, {'Ž', 'Z'}, + {'ā', 'a'}, {'č', 'c'}, {'ē', 'e'}, {'ģ', 'g'}, {'ī', 'i'}, {'ķ', 'k'}, {'ļ', 'l'}, {'ņ', 'n'}, {'š', 's'}, {'ū', 'u'}, {'ž', 'z'} + }; + + static { + //noinspection ComparatorCombinators + Arrays.sort(CHARS, (char[] o1, char[] o2) -> (int) o1[0] - (int) o2[0]); + } + + public static String process(String text, String delimiter) { + text = Normalizer.normalize(text, Normalizer.Form.NFC); + return SYMBOLS.matcher(transliterate(text)).replaceAll(delimiter); + } + + public static void transliterate(StringBuilder builder, CharSequence string) { + int length = string.length(); + for (int i = 0; i < length; ++i) { + put(builder, string.charAt(i)); + } + } + + public static CharSequence transliterate(CharSequence string) { + StringBuilder builder = new StringBuilder(string.length() + 10); + transliterate(builder, string); + return builder; + } + + private static void put(StringBuilder output, char chr) { + int l = 0, r = CHARS.length - 1; + if (chr >= CHARS[0][0]) { + while (l <= r) { + int m = (r + l) >> 1; + char[] item = CHARS[m]; + if (chr < item[0]) { + r = m - 1; + } else if (chr > item[0]) { + l = m + 1; + } else { + output.append(item, 1, item.length - 1); + return; + } + } + } + output.append(chr); + } + + /* keyboard + [ + 'ru' => [ + 'code' => 'rus', + 'inverted' => [ + 'q'=>'й','w'=>'ц','e'=>'у','r'=>'к','t'=>'е','y'=>'н','u'=>'г','i'=>'ш','o'=>'щ','p'=>'з','['=>'х','{'=>'х',']'=>'ъ','}'=>'ъ', + 'a'=>'ф','s'=>'ы','d'=>'в','f'=>'а','g'=>'п','h'=>'р','j'=>'о','k'=>'л','l'=>'д',';'=>'ж',':'=>'ж',"'"=>'э','"'=>'э', + 'z'=>'я','x'=>'ч','c'=>'с','v'=>'м','b'=>'и','n'=>'т','m'=>'ь',','=>'б','<'=>'б','.'=>'ю','>'=>'ю','`'=>'ё','~'=>'ё' + ] + ], + 'uk' => [ + 'code' => 'ukr', + 'inverted' => [ + 'q'=>'й','w'=>'ц','e'=>'у','r'=>'к','t'=>'е','y'=>'н','u'=>'г','i'=>'ш','o'=>'щ','p'=>'з','['=>'х','{'=>'х',']'=>'ї','}'=>'ї', + 'a'=>'ф','s'=>'і','d'=>'в','f'=>'а','g'=>'п','h'=>'р','j'=>'о','k'=>'л','l'=>'д',';'=>'ж',':'=>'ж',"'"=>'є','"'=>'є', + 'z'=>'я','x'=>'ч','c'=>'с','v'=>'м','b'=>'и','n'=>'т','m'=>'ь',','=>'б','<'=>'б','.'=>'ю','>'=>'ю','\\'=>'ґ','|'=>'ґ' + ] + ] + ] + */ +} diff --git a/src/main/java/ua/net/uid/utils/helpers/XmlHelper.java b/src/main/java/ua/net/uid/utils/helpers/XmlHelper.java new file mode 100644 index 0000000..384936d --- /dev/null +++ b/src/main/java/ua/net/uid/utils/helpers/XmlHelper.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.helpers; + +import java.io.IOException; + +public class XmlHelper { + private XmlHelper() { + } + + public static void escape(Appendable builder, CharSequence string, int start, int end) throws IOException { + for (int i = start; i < end; ++i) { + char chr = string.charAt(i); + String entity; + switch (chr) { + case '&': + entity = "&"; + break; + case '<': + entity = "<"; + break; + case '>': + entity = ">"; + break; + case '"': + entity = """; + break; + case '\'': + entity = "'"; + break; + default: + continue; + } + if (start < i) builder.append(string, start, i); + start = i + 1; + builder.append(entity); + } + if (start < end) builder.append(string, start, end); + } + + public static void escape(Appendable builder, CharSequence string) throws IOException { + escape(builder, string, 0, string.length()); + } + + public static String escape(CharSequence string, int start, int end) { + StringBuilder builder = new StringBuilder(string.length()); + try { + escape(builder, string, start, end); + } catch (IOException ignored) { + } + return builder.toString(); + } + + public static String escape(CharSequence string) { + return escape(string, 0, string.length()); + } +} diff --git a/src/main/java/ua/net/uid/utils/io/ExpiringCache.java b/src/main/java/ua/net/uid/utils/io/ExpiringCache.java new file mode 100644 index 0000000..9fa4fa3 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/io/ExpiringCache.java @@ -0,0 +1,327 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.io; + +import ua.net.uid.utils.concurrent.ReadyFuture; + +import java.util.Date; +import java.util.Objects; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class ExpiringCache { + static final int NCPU = Runtime.getRuntime().availableProcessors(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final AtomicInteger count = new AtomicInteger(); + private final ExecutorService executor; + private Chain[] table; + + public ExpiringCache() { + this(Executors.newCachedThreadPool()); + } + + public ExpiringCache(ExecutorService executor) { + this.executor = executor; + table = new Chain[NCPU * 2]; + } + + public Future future(K key) { + return chain(key).get(System.currentTimeMillis(), key); + } + + public Future future(K key, Callable callable) { + return chain(key).future(System.currentTimeMillis(), key, callable, Long.MAX_VALUE); + } + + public Future future(K key, Callable callable, long ttl) { + long now; + return chain(key).future(now = System.currentTimeMillis(), key, callable, now + ttl); + } + + public Future future(K key, Callable callable, Date expiry) { + return chain(key).future(System.currentTimeMillis(), key, callable, expiry.getTime()); + } + + public V get(K key) { + Future future = future(key); + return future == null ? null : value(future); + } + + public V get(K key, Callable callable) { + return value(future(key, callable)); + } + + public V get(K key, Callable callable, long ttl) { + return value(future(key, callable, ttl)); + } + + public V get(K key, Callable callable, Date expiry) { + return value(future(key, callable, expiry)); + } + + public void set(K key, V value) { + chain(key).set(System.currentTimeMillis(), key, value, Long.MAX_VALUE); + } + + public void set(K key, V value, long ttl) { + long now; + chain(key).set(now = System.currentTimeMillis(), key, value, now + ttl); + } + + public void set(K key, V value, Date expiry) { + chain(key).set(System.currentTimeMillis(), key, value, expiry.getTime()); + } + + public void put(K key, Callable callable) { + chain(key).put(System.currentTimeMillis(), key, callable, Long.MAX_VALUE); + } + + public void put(K key, Callable callable, long ttl) { + long now; + chain(key).put(now = System.currentTimeMillis(), key, callable, now + ttl); + } + + public void put(K key, Callable callable, Date expiry) { + chain(key).put(System.currentTimeMillis(), key, callable, expiry.getTime()); + } + + public Future extractFuture(K key) { + return chain(key).extract(System.currentTimeMillis(), key); + } + + public V extract(K key) { + Future future = extractFuture(key); + return future == null ? null : value(future); + } + + public void remove(K key) { + chain(key).remove(System.currentTimeMillis(), key); + } + + public void clear() { + lock.writeLock().lock(); + try { + for (Chain chain : table) { + chain.clear(); + } + //count.set(0); + } finally { + lock.writeLock().unlock(); + } + } + + public int count() { + return count.get(); + } + + public void gc() { + lock.readLock().lock(); + try { + long now = System.currentTimeMillis(); + for (Chain chain : table) { + chain.gc(now); + } + } finally { + lock.readLock().unlock(); + } + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private Chain chain(K key) { + int hash = key.hashCode(); + lock.readLock().lock(); + try { + return table[hash % table.length]; + } finally { + lock.readLock().unlock(); + } + } + + private V value(Future future) { + try { + return future.get(); + } catch (ExecutionException | InterruptedException ex) { + throw new RuntimeException(ex); + } + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private static abstract class Item { + Entry next; + Item(Entry next) { this.next = next; } + } + + private final static class Entry extends Item { + final K key; + Future future; + long expiry; + + private Entry(K key, Future future, long expiry, Entry next) { + super(next); + this.key = key; + this.future = future; + this.expiry = expiry; + } + } + + private final static class Chain extends Item { + private final ExpiringCache cache; + private int count = 0; + + Chain(ExpiringCache cache, Entry next) { + super(next); + this.cache = cache; + } + + synchronized Future get(long now, K key) { + Item item = this; + int cnt = 0; + while (next(now, item)) { + if (Objects.equals(key, item.next.key)) { + return item.next.future; + } + ++cnt; + item = item.next; + } + count(cnt); + return null; + } + + synchronized Future future(long now, K key, Callable callable, long expiry) { + Item item = this, last = this; + int cnt = 0; + while (next(now, item)) { + if (Objects.equals(key, item.next.key)) { + return item.next.future; + } + ++cnt; + if (item.next.expiry > expiry) { + last = item.next; + } + item = item.next; + } + last.next = new Entry<>(key, cache.executor.submit(callable), expiry, last.next); + count(cnt + 1); + return last.next.future; + } + + synchronized void set(long now, K key, V value, long expiry) { + Item item = this, last = this; + int cnt = 0; + while (next(now, item)) { + if (Objects.equals(key, item.next.key)) { + item.next = item.next.next; + continue; + } + ++cnt; + if (item.next.expiry > expiry) { + last = item.next; + } + item = item.next; + } + last.next = new Entry<>(key, new ReadyFuture<>(value), expiry, last.next); + count(cnt + 1); + } + + synchronized void put(long now, K key, Callable callable, long expiry) { + Item item = this, last = this; + int cnt = 0; + while (next(now, item)) { + if (Objects.equals(key, item.next.key)) { + item.next = item.next.next; + continue; + } + ++cnt; + if (item.next.expiry > expiry) { + last = item.next; + } + item = item.next; + } + last.next = new Entry<>(key, cache.executor.submit(callable), expiry, last.next); + count(cnt + 1); + } + + synchronized Future extract(long now, K key) { + Item item = this; + int cnt = 0; + while (next(now, item)) { + if (Objects.equals(key, item.next.key)) { + try { + return item.next.future; + } finally { + item.next = item.next.next; + --count; + cache.count.decrementAndGet(); + } + } + ++cnt; + item = item.next; + } + count(cnt); + return null; + } + + synchronized void remove(long now, K key) { + Item item = this; + int cnt = 0; + while (next(now, item)) { + if (Objects.equals(key, item.next.key)) { + item.next = item.next.next; + --count; + cache.count.decrementAndGet(); + return; + } + ++cnt; + item = item.next; + } + count(cnt); + } + + void gc(long now) { + Item item = this; + int cnt = 0; + while (next(now, item)) { + ++cnt; + item = item.next; + } + count(cnt); + } + + void clear() { + cache.count.addAndGet(-count); + count = 0; + next = null; + } + + private boolean next(long now, Item current) { + if (current.next != null) { + if (current.next.expiry <= now) { + current.next = null; + } else { + return true; + } + } + return false; + } + + private void count(int value) { + if (count != value) { + cache.count.addAndGet(value - count); + count = value; + } + } + } +} diff --git a/src/main/java/ua/net/uid/utils/io/InternPool.java b/src/main/java/ua/net/uid/utils/io/InternPool.java new file mode 100644 index 0000000..a85a25d --- /dev/null +++ b/src/main/java/ua/net/uid/utils/io/InternPool.java @@ -0,0 +1,79 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.io; + +import java.lang.ref.WeakReference; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class InternPool { + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final Map> pool = new WeakHashMap<>(); + + public V intern(V item) { + if (item != null) { + lock.readLock().lock(); + try { + WeakReference cached = pool.get(item); + V result; + if (cached != null && (result = cached.get()) != null) + return result; + } finally { + lock.readLock().unlock(); + } + lock.writeLock().lock(); + try { + WeakReference cached = pool.get(item); + V result; + if (cached != null && (result = cached.get()) != null) + return result; + pool.put(item, new WeakReference<>(item)); + } finally { + lock.writeLock().unlock(); + } + } + return item; + } + + public void remove(V item) { + lock.writeLock().lock(); + try { + pool.remove(item); + } finally { + lock.writeLock().unlock(); + } + } + + public void clear() { + lock.writeLock().lock(); + try { + pool.clear(); + } finally { + lock.writeLock().unlock(); + } + } + + public int size() { + lock.readLock().lock(); + try { + return pool.size(); + } finally { + lock.readLock().unlock(); + } + } +} diff --git a/src/main/java/ua/net/uid/utils/io/LocalCache.java b/src/main/java/ua/net/uid/utils/io/LocalCache.java new file mode 100644 index 0000000..6236512 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/io/LocalCache.java @@ -0,0 +1,88 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.io; + +import ua.net.uid.utils.concurrent.ReadyFuture; + +import java.util.Map; +import java.util.concurrent.*; + +public class LocalCache { + private final ExecutorService executor; + private final Map> items = new ConcurrentHashMap<>(); + + public LocalCache() { + this(Executors.newCachedThreadPool()); + } + + public LocalCache(ExecutorService executor) { + this.executor = executor; + } + + public Future future(K key) { + return items.get(key); + } + + public Future future(K key, Callable callable) { + return items.computeIfAbsent(key, (K k) -> executor.submit(callable)); + } + + public V get(K key) { + Future future = future(key); + return future == null ? null : value(future); + } + + public V get(K key, Callable callable) { + return value(future(key, callable)); + } + + public void set(K key, V value) { + items.put(key, new ReadyFuture<>(value)); + } + + public void put(K key, Callable callable) { + items.put(key, executor.submit(callable)); + } + + public Future extractFuture(K key) { + return items.remove(key); + } + + public V extract(K key) { + Future future = extractFuture(key); + return future == null ? null : value(future); + } + + public void remove(K key) { + items.remove(key); + } + + public void clear() { + items.clear(); + } + + public int count() { + return items.size(); + } + + private V value(Future future) { + try { + return future.get(); + } catch (ExecutionException | InterruptedException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/src/main/java/ua/net/uid/utils/io/SimpleWriter.java b/src/main/java/ua/net/uid/utils/io/SimpleWriter.java new file mode 100644 index 0000000..2c3536c --- /dev/null +++ b/src/main/java/ua/net/uid/utils/io/SimpleWriter.java @@ -0,0 +1,114 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.io; + +import java.io.Writer; + +public class SimpleWriter extends Writer implements CharSequence { + private final StringBuilder builder; + + public SimpleWriter() { + this(new StringBuilder()); + } + + public SimpleWriter(int initCapacity) { + this(new StringBuilder(initCapacity)); + } + + public SimpleWriter(StringBuilder builder) { + this.builder = builder; + this.lock = this.builder; + } + + @Override + public void write(int c) { + builder.append((char) c); + } + + @Override + public void write(char[] buf) { + builder.append(buf); + } + + @Override + public void write(char[] buf, int off, int len) { + builder.append(buf, off, len); + } + + @Override + public void write(String str) { + builder.append(str); + } + + @Override + public void write(String str, int off, int len) { + builder.append(str, off, off + len); + } + + @Override + public SimpleWriter append(CharSequence csq) { + builder.append(csq); + return this; + } + + @Override + public SimpleWriter append(CharSequence csq, int start, int end) { + builder.append(csq, start, end); + return this; + } + + @Override + public SimpleWriter append(char c) { + builder.append(c); + return this; + } + + @Override + public void flush() { + } + + @Override + public void close() { + } + + @Override + public int length() { + return builder.length(); + } + + @Override + public char charAt(int index) { + return builder.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return builder.subSequence(start, end); + } + + @Override + public String toString() { + return builder.toString(); + } + + public StringBuilder getBuilder() { + return builder; + } + + public char[] toCharArray() { + return toString().toCharArray(); + } +} diff --git a/src/main/java/ua/net/uid/utils/iterators/AbstractFilteredIterator.java b/src/main/java/ua/net/uid/utils/iterators/AbstractFilteredIterator.java new file mode 100644 index 0000000..a7302f9 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/iterators/AbstractFilteredIterator.java @@ -0,0 +1,62 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public abstract class AbstractFilteredIterator implements Iterator { + private final Iterator iterator; + private T next; + private int flag = 0; + + public AbstractFilteredIterator(Iterator iterator) { + this.iterator = iterator; + } + + @Override + public boolean hasNext() { + if (flag != 1) { + flag = 3; + while (iterator.hasNext()) { + T item = iterator.next(); + if (check(item)) { + next = item; + flag = 1; + break; + } + } + } + return flag != 3; + } + + protected abstract boolean check(T item); + + @Override + public T next() { + if (!hasNext()) + throw new NoSuchElementException(); + flag = 2; + return next; + } + + @Override + public void remove() { + if (flag != 2) + throw new IllegalStateException(); + iterator.remove(); + } +} diff --git a/src/main/java/ua/net/uid/utils/iterators/AbstractTransformIterator.java b/src/main/java/ua/net/uid/utils/iterators/AbstractTransformIterator.java new file mode 100644 index 0000000..14c675c --- /dev/null +++ b/src/main/java/ua/net/uid/utils/iterators/AbstractTransformIterator.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.iterators; + +import java.util.Iterator; + +public abstract class AbstractTransformIterator implements Iterator { + private final Iterator iterator; + + public AbstractTransformIterator(Iterator iterator) { + this.iterator = iterator; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public T next() { + return transform(iterator.next()); + } + + protected abstract T transform(S source); + + @Override + public void remove() { + iterator.remove(); + } +} diff --git a/src/main/java/ua/net/uid/utils/iterators/ArrayIterator.java b/src/main/java/ua/net/uid/utils/iterators/ArrayIterator.java new file mode 100644 index 0000000..765d899 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/iterators/ArrayIterator.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class ArrayIterator implements Iterator { + private final E[] items; + private int offset = 0; + + public ArrayIterator(E[] items) { + this.items = items; + } + + @Override + public boolean hasNext() { + return offset < items.length; + } + + @Override + public E next() { + if (offset >= items.length) { + throw new NoSuchElementException(); + } else { + return items[offset++]; + } + } +} diff --git a/src/main/java/ua/net/uid/utils/tools/DailyEquation.java b/src/main/java/ua/net/uid/utils/tools/DailyEquation.java new file mode 100644 index 0000000..90eefeb --- /dev/null +++ b/src/main/java/ua/net/uid/utils/tools/DailyEquation.java @@ -0,0 +1,151 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.tools; + +import java.util.Calendar; + +/** + * + * + * https://web.archive.org/web/20161202180207/http://williams.best.vwh.net/sunrise_sunset_algorithm.htm + * http://edwilliams.org/sunrise_sunset_algorithm.htm + * https://edwilliams.org/sunrise_sunset_example.htm + * + * https://github.com/KlausBrunner/solarpositioning + * https://github.com/mikereedell/sunrisesunsetlib-java + * https://github.com/shred/commons-suncalc + * https://gist.github.com/Tafkas/4742250 + * + * https://github.com/caarmen/SunriseSunset + * http://users.electromagnetic.net/bu/astro/sunrise-set.php + * + * + * https://www.aa.quae.nl/en/reken/zonpositie.html + * + * @author nightfall + */ +public class DailyEquation { + //////////////////////////////////////////////////////////////////////////// + public enum Zenith { + ASTRONOMICAL(108.), // Astronomical sunrise/set is when the sun is 18 degrees below the horizon. + NAUTICAL(102.), // Nautical sunrise/set is when the sun is 12 degrees below the horizon. + CIVIL(96.), // Civil sunrise/set (dawn/dusk) is when the sun is 6 degrees below the horizon. + OFFICIAL(90.8333); // Official sunrise/set is when the sun is 50' below the horizon. + + private final double degrees; + Zenith(double degrees) { this.degrees = degrees; } + public double getDegrees() { return degrees; } + } + //////////////////////////////////////////////////////////////////////////// + public enum Type { + NORMAL_DAY("normal"), + POLAR_NIGHT("night"), + POLAR_DAY("day"); + private final String title; + Type(String title) { this.title = title; } + public String getTitle() { return title; } + } + //////////////////////////////////////////////////////////////////////////// + public static class Events { + private final Long sunrise; + private final Long sunset; + private final Type type; + Events(Long sunrise, Long sunset, Type type) { + this.sunrise = sunrise; + this.sunset = sunset; + this.type = type; + } + public Long getSunrise() { return sunrise; } + public Long getSunset() { return sunset; } + public Type getType() { return type; } + } + //////////////////////////////////////////////////////////////////////////// + public static Events getSunEvents(double latitude, double longitude, Calendar calendar, Zenith zenith) { + return getSunEvents(latitude, longitude, calendar, zenith.getDegrees()); + } + public static Events getSunEvents(double latitude, double longitude, Calendar calendar, double zenith) { + longitude /= 15; + int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); + + double sunrizeTime = calculateEvent(latitude, longitude, zenith, dayOfYear, true); + double sunsetTime = calculateEvent(latitude, longitude, zenith, dayOfYear, false); + + if (sunrizeTime == Double.NEGATIVE_INFINITY || sunsetTime == Double.NEGATIVE_INFINITY) { // the sun never rises on this location (on the specified date) + return new Events(null, null, Type.POLAR_NIGHT); + } else if (sunrizeTime == Double.POSITIVE_INFINITY || sunsetTime == Double.POSITIVE_INFINITY) { // the sun never sets on this location (on the specified date) + return new Events(null, null, Type.POLAR_DAY); + } else { + return new Events(convertDate(calendar, sunrizeTime), convertDate(calendar, sunsetTime), Type.NORMAL_DAY); + } + } + + protected static double calculateEvent(double latitude, double baseLongitudeHour, double zenith, int dayOfYear, boolean rising) { + //t = ((rising ? 6 : 18) - lngHour) / 24 + dayOfYear; + double longitudeHour = ((rising ? 6 : 18) - baseLongitudeHour) / 24 + dayOfYear; + // M = 0.9856 * t - 3.289; + double meanAnomaly = 0.9856 * longitudeHour - 3.289; + double meanAnomalyRadians = Math.toRadians(meanAnomaly); + // L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634 + double sunTrueLong = meanAnomaly + (1.916 * Math.sin(meanAnomalyRadians)) + (0.020 * Math.sin(2 * meanAnomalyRadians)) + 282.634; // L + if (sunTrueLong > 360) sunTrueLong -= 360; + + // sinDec = 0.39782 * sin(L); + double sinSunDeclination = 0.39782 * Math.sin(Math.toRadians(sunTrueLong)); + // cosDec = cos(asin(sinDec)); + double cosineSunDeclination = Math.cos(Math.asin(sinSunDeclination)); + // cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude)); + double latitudeRadians = Math.toRadians(latitude); + double cosineSunLocalHour = (Math.cos(Math.toRadians(zenith)) - sinSunDeclination * Math.sin(latitudeRadians)) + / (cosineSunDeclination * Math.cos(latitudeRadians)); + + if (cosineSunLocalHour > 1) return Double.NEGATIVE_INFINITY; // the sun never rises on this location (on the specified date) + if (cosineSunLocalHour < -1) return Double.POSITIVE_INFINITY; // the sun never sets on this location (on the specified date) + + // H = (rising ? 360 - acos(cosH) : acos(cosH)) / 15; + double sunLocalHour = Math.toDegrees(Math.acos(cosineSunLocalHour)); + sunLocalHour = (rising ? 360 - sunLocalHour : sunLocalHour) / 15; + + // RA = atan(0.91764 * tan(L)); // RA + //double rightAscension = Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) ))); + double rightAscension = Math.toDegrees(Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) )))); + + //--- //RA potentially needs to be adjusted into the range [0,360) by adding/subtracting 360 + //--- if (rightAscension < 0) { rightAscension += 360; } else if (rightAscension > 360) { rightAscension -= 360; } + // RA = (RA + (floor(L/90) - floor(RA/90)) * 90) / 15; + rightAscension = (rightAscension + (Math.floor(sunTrueLong / 90) - Math.floor(rightAscension / 90)) * 90) / 15; + + // T = H + RA - (0.06571 * t) - 6.622 + double localMeanTime = sunLocalHour + rightAscension - (longitudeHour * 0.06571) - 6.622; // T + + // UT = T - lngHour + return localMeanTime - baseLongitudeHour; + } + + private static final int DAYMSEC = 24 * 60 * 60 * 1000; + protected static long convertDate(Calendar calendar, double utcTime) { + // localT = UT + localOffset + int time = (int)(utcTime * 3600000) + calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); + // UT potentially needs to be adjusted into the range [0,24) by adding/subtracting 24 + //if (utcTime >= 24.) utcTime -= 24; else if (utcTime < 0) utcTime += 24; + if (time >= DAYMSEC) time -= DAYMSEC; else if (time < 0) time += DAYMSEC; + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + calendar.add(Calendar.MILLISECOND, time); + return calendar.getTimeInMillis(); + } +} diff --git a/src/main/java/ua/net/uid/utils/tools/Mask.java b/src/main/java/ua/net/uid/utils/tools/Mask.java new file mode 100644 index 0000000..ce71b01 --- /dev/null +++ b/src/main/java/ua/net/uid/utils/tools/Mask.java @@ -0,0 +1,255 @@ +/* + * Copyright 2019 nightfall. + * + * Licensed 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 + * + * http://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 ua.net.uid.utils.tools; + +import ua.net.uid.utils.Setter; +import ua.net.uid.utils.helpers.RegexHelper; + +import java.util.Arrays; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public interface Mask { + boolean check(String value); + + default boolean check(String value, Setter setter) { + return check(value); + } + + @Override + boolean equals(Object obj); + + @Override + int hashCode(); + + class Any implements Mask { + @Override + public boolean check(String value) { + return true; + } + + @Override + public boolean equals(Object another) { + return another instanceof Any; + } + + @Override + public int hashCode() { + return 5; + } + } + + class Match implements Mask { + private final String pattern; + + public Match(String pattern) { + this.pattern = pattern; + } + + @Override + public boolean check(String value) { + return pattern.equals(value); + } + + @Override + public boolean equals(Object another) { + return another instanceof Match && pattern.equals(((Match) another).pattern); + } + + @Override + public int hashCode() { + return 23 * 5 + this.pattern.hashCode(); + } + } + + class IgnoreCase implements Mask { + private final String pattern; + + public IgnoreCase(String pattern) { + this.pattern = pattern.toLowerCase(); + } + + @Override + public boolean check(String value) { + return pattern.equalsIgnoreCase(value); + } + + @Override + public boolean equals(Object another) { + return another instanceof IgnoreCase && pattern.equals(((IgnoreCase) another).pattern); + } + + @Override + public int hashCode() { + return 37 * 3 + this.pattern.hashCode(); + } + } + + class Prefix implements Mask { + private final String prefix; + + public Prefix(String prefix) { + this.prefix = prefix; + } + + @Override + public boolean check(String value) { + return value.startsWith(prefix); + } + + @Override + public boolean equals(Object another) { + return another instanceof Prefix && prefix.equals(((Prefix) another).prefix); + } + + @Override + public int hashCode() { + return 59 * 7 + prefix.hashCode(); + } + } + + class Suffix implements Mask { + private final String suffix; + + public Suffix(String suffix) { + this.suffix = suffix; + } + + @Override + public boolean check(String value) { + return value.endsWith(suffix); + } + + @Override + public boolean equals(Object another) { + return another instanceof Suffix && suffix.equals(((Suffix) another).suffix); + } + + @Override + public int hashCode() { + return 53 * 5 + suffix.hashCode(); + } + } + + class Regexp implements Mask { + private final Pattern pattern; + private final Set groups; + + public Regexp(Pattern pattern) { + this.pattern = pattern; + this.groups = RegexHelper.getNamedGroupsSet(pattern); + } + + public Regexp(String pattern) { + this(Pattern.compile(pattern)); + } + + public Regexp(String pattern, int flags) { + this(Pattern.compile(pattern, flags)); + } + + @Override + public boolean check(String value) { + return check(value, null); + } + + @Override + public boolean check(String value, Setter setter) { + final Matcher matcher = pattern.matcher(value); + if (matcher.matches()) { + if (setter != null && !groups.isEmpty()) { + for (String group : groups) + setter.set(group, matcher.group(group)); + } + return true; + } + return false; + } + + @Override + public boolean equals(Object another) { + return another instanceof Regexp && pattern.equals(((Regexp) another).pattern); + } + + @Override + public int hashCode() { + return 97 * 7 + this.pattern.hashCode(); + } + } + + class Or implements Mask { + private final Mask[] items; + + public Or(Mask... items) { + this.items = items; + } + + @Override + public boolean check(String value) { + return check(value, null); + } + + @Override + public boolean check(String value, Setter setter) { + for (Mask mask : items) { + if (mask.check(value, setter)) return true; + } + return false; + } + + @Override + public int hashCode() { + return 61 * 7 + Arrays.deepHashCode(items); + } + + @Override + public boolean equals(Object another) { + return another instanceof Or && Arrays.deepEquals(items, ((Or) another).items); + } + } + + class And implements Mask { + private final Mask[] items; + + public And(Mask... items) { + this.items = items; + } + + @Override + public boolean check(String value) { + return check(value, null); + } + + @Override + public boolean check(String value, Setter setter) { + for (Mask mask : items) { + if (!mask.check(value, setter)) return false; + } + return true; + } + + @Override + public int hashCode() { + return 67 * 3 + Arrays.deepHashCode(items); + } + + @Override + public boolean equals(Object another) { + return another instanceof And && Arrays.deepEquals(items, ((And) another).items); + } + } +} diff --git a/src/test/java/ua/net/uid/utils/concurrent/ReadyFutureTest.java b/src/test/java/ua/net/uid/utils/concurrent/ReadyFutureTest.java new file mode 100644 index 0000000..c1e15cc --- /dev/null +++ b/src/test/java/ua/net/uid/utils/concurrent/ReadyFutureTest.java @@ -0,0 +1,41 @@ +package ua.net.uid.utils.concurrent; + +import org.junit.jupiter.api.Test; + +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.*; + +class ReadyFutureTest { + + @Test + void testCancel() { + ReadyFuture instance = new ReadyFuture(null); + assertFalse(instance.cancel(true)); + assertFalse(instance.cancel(false)); + } + + @Test + void testIsCancelled() { + ReadyFuture instance = new ReadyFuture(null); + assertFalse(instance.isCancelled()); + } + + @Test + void testIsDone() { + ReadyFuture instance = new ReadyFuture(null); + assertTrue(instance.isDone()); + } + + @Test + void testGet() { + ReadyFuture instance = new ReadyFuture(3); + assertEquals(3, instance.get()); + } + + @Test + void testGet_long_TimeUnit() { + ReadyFuture instance = new ReadyFuture(4.4); + assertEquals(4.4, instance.get(1, TimeUnit.NANOSECONDS)); + } +} diff --git a/src/test/java/ua/net/uid/utils/helpers/ArrayHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/ArrayHelperTest.java new file mode 100644 index 0000000..a7e1147 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/ArrayHelperTest.java @@ -0,0 +1,68 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ArrayHelperTest { + final String[] source = new String[]{"v2", "v5", "v4", "v1", null, "v3", "v2", "v5", "v4", "v1", null, "v3"}; + + @Test + void indexOf() { + assertEquals(3, ArrayHelper.indexOf(source, "v1")); + assertEquals(0, ArrayHelper.indexOf(source, "v2")); + assertEquals(-1, ArrayHelper.indexOf(source, "s1")); + assertEquals(4, ArrayHelper.indexOf(source, null)); + } + + @Test + void indexOfFrom() { + assertEquals(-1, ArrayHelper.indexOf(source, "s1", 2)); + assertEquals(3, ArrayHelper.indexOf(source, "v1", 3)); + assertEquals(6, ArrayHelper.indexOf(source, "v2", 3)); + assertEquals(4, ArrayHelper.indexOf(source, null, 4)); + assertEquals(10, ArrayHelper.indexOf(source, null, 5)); + assertEquals(-1, ArrayHelper.indexOf(source, null, 11)); + } + + @Test + void lastIndexOf() { + assertEquals(9, ArrayHelper.lastIndexOf(source, "v1")); + assertEquals(6, ArrayHelper.lastIndexOf(source, "v2")); + assertEquals(-1, ArrayHelper.lastIndexOf(source, "s1")); + assertEquals(10, ArrayHelper.lastIndexOf(source, null)); + } + + @Test + void lastIndexOfFrom() { + assertEquals(-1, ArrayHelper.lastIndexOf(source, "s1", 2)); + assertEquals(3, ArrayHelper.lastIndexOf(source, "v1", 3)); + assertEquals(0, ArrayHelper.lastIndexOf(source, "v2", 3)); + assertEquals(4, ArrayHelper.lastIndexOf(source, null, 4)); + assertEquals(-1, ArrayHelper.lastIndexOf(source, null, 3)); + assertEquals(10, ArrayHelper.lastIndexOf(source, null, 11)); + } + + /* + @Test + void testCollectionToArray() { + List source = Arrays.asList("v2", "v5", "v4", "v1", "v3"); + String[] target = ArrayHelper.toArray(source); + assertArrayEquals(new String[]{"v2", "v5", "v4", "v1", "v3"}, target); + } + + @Test + void testCollectionToSortedArray() { + List source = Arrays.asList("v2", "v5", "v4", "v1", "v3"); + String[] target = ArrayHelper.toSortedArray(source); + assertArrayEquals(new String[]{"v1", "v2", "v3", "v4", "v5"}, target); + } + + @Test + void testCollectionToSortedArrayWithComparator() { + List source = Arrays.asList("v2", "v5", "v4", "v1", "v3"); + @SuppressWarnings("ComparatorCombinators") String[] target = ArrayHelper.toSortedArray(source, (String o1, String o2) -> o2.compareTo(o1)); + assertArrayEquals(new String[]{"v5", "v4", "v3", "v2", "v1"}, target); + } + */ +} diff --git a/src/test/java/ua/net/uid/utils/helpers/CastTest.java b/src/test/java/ua/net/uid/utils/helpers/CastTest.java new file mode 100644 index 0000000..ff0a055 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/CastTest.java @@ -0,0 +1,171 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Locale; + +import static org.junit.jupiter.api.Assertions.*; + +class CastTest { + @Test + void testToBoolean() { + assertNull(Cast.toBoolean(null, null)); + assertNull(Cast.toBoolean("", null)); + assertNull(Cast.toBoolean("qwe", null)); + assertTrue(Cast.toBoolean(null, true)); + assertTrue(Cast.toBoolean("", true)); + assertTrue(Cast.toBoolean("qwe", true)); + assertFalse(Cast.toBoolean(null, false)); + assertFalse(Cast.toBoolean("", false)); + assertFalse(Cast.toBoolean("qwe", false)); + assertTrue(Cast.toBoolean("true", false)); + assertTrue(Cast.toBoolean("t", false)); + assertTrue(Cast.toBoolean("yes", false)); + assertTrue(Cast.toBoolean("y", false)); + assertTrue(Cast.toBoolean("122", false)); + assertTrue(Cast.toBoolean("+", false)); + assertFalse(Cast.toBoolean("false", true)); + assertFalse(Cast.toBoolean("f", true)); + assertFalse(Cast.toBoolean("no", true)); + assertFalse(Cast.toBoolean("n", true)); + assertFalse(Cast.toBoolean("0000", true)); + assertFalse(Cast.toBoolean("-", true)); + } + + @Test + void testToByte() { + assertNull(Cast.toByte(null, null)); + assertNull(Cast.toByte("", null)); + assertNull(Cast.toByte("qwe", null)); + assertEquals((Object) (byte) 33, Cast.toByte(null, (byte) 33)); + assertEquals((Object) (byte) 34, Cast.toByte("", (byte) 34)); + assertEquals((Object) (byte) 35, Cast.toByte("qwe", (byte) 35)); + assertEquals((Object) (byte) 12, Cast.toByte("12", (byte) 36)); + assertEquals((Object) (byte) 0, Cast.toByte("0", (byte) 37)); + } + + @Test + void testToShort() { + assertNull(Cast.toShort(null, null)); + assertNull(Cast.toShort("", null)); + assertNull(Cast.toShort("qwe", null)); + assertEquals((Object) (short) 33, Cast.toShort(null, (short) 33)); + assertEquals((Object) (short) 34, Cast.toShort("", (short) 34)); + assertEquals((Object) (short) 35, Cast.toShort("qwe", (short) 35)); + assertEquals((Object) (short) 12, Cast.toShort("12", (short) 36)); + assertEquals((Object) (short) 0, Cast.toShort("0", (short) 37)); + } + + @Test + void testToInteger() { + assertNull(Cast.toInteger(null, null)); + assertNull(Cast.toInteger("", null)); + assertNull(Cast.toInteger("qwe", null)); + assertEquals((Object) (int) 33, Cast.toInteger(null, 33)); + assertEquals((Object) (int) 34, Cast.toInteger("", 34)); + assertEquals((Object) (int) 35, Cast.toInteger("qwe", 35)); + assertEquals((Object) (int) 12, Cast.toInteger("12", 36)); + assertEquals((Object) (int) 0, Cast.toInteger("0", 37)); + } + + @Test + void testToLong() { + assertNull(Cast.toLong(null, null)); + assertNull(Cast.toLong("", null)); + assertNull(Cast.toLong("qwe", null)); + assertEquals((Object) (long) 33, Cast.toLong(null, (long) 33)); + assertEquals((Object) (long) 34, Cast.toLong("", (long) 34)); + assertEquals((Object) (long) 35, Cast.toLong("qwe", (long) 35)); + assertEquals((Object) (long) 12, Cast.toLong("12", (long) 36)); + assertEquals((Object) (long) 0, Cast.toLong("0", (long) 37)); + } + + @Test + void testToFloat() { + assertNull(Cast.toFloat(null, null)); + assertNull(Cast.toFloat("", null)); + assertNull(Cast.toFloat("qwe", null)); + assertEquals((Object) (float) 33.1, Cast.toFloat(null, (float) 33.1)); + assertEquals((Object) (float) 34.1, Cast.toFloat("", (float) 34.1)); + assertEquals((Object) (float) 35.1, Cast.toFloat("qwe", (float) 35.1)); + assertEquals((Object) (float) 12.2, Cast.toFloat("12.2", (float) 36.1)); + assertEquals((Object) (float) 0.2, Cast.toFloat("0.2", (float) 37.1)); + assertEquals((Object) (float) 0.0, Cast.toFloat("0.0", (float) 38.1)); + } + + @Test + void testToDouble() { + assertNull(Cast.toDouble(null, null)); + assertNull(Cast.toDouble("", null)); + assertNull(Cast.toDouble("qwe", null)); + assertEquals((Object) (double) 33.1, Cast.toDouble(null, 33.1)); + assertEquals((Object) (double) 34.1, Cast.toDouble("", 34.1)); + assertEquals((Object) (double) 35.1, Cast.toDouble("qwe", 35.1)); + assertEquals((Object) (double) 12.2, Cast.toDouble("12.2", 36.1)); + assertEquals((Object) (double) 0.2, Cast.toDouble("0.2", 37.1)); + assertEquals((Object) (double) 0.0, Cast.toDouble("0.0", 38.1)); + } + + @Test + void testToBigInteger() { + assertNull(Cast.toBigInteger(null, null)); + assertNull(Cast.toBigInteger("", null)); + assertNull(Cast.toBigInteger("qwe", null)); + assertEquals(BigInteger.ZERO, Cast.toBigInteger(null, BigInteger.ZERO)); + assertEquals(BigInteger.ONE, Cast.toBigInteger("", BigInteger.ONE)); + assertEquals(BigInteger.TEN, Cast.toBigInteger("qwe", BigInteger.TEN)); + assertEquals(BigInteger.valueOf(12), Cast.toBigInteger("12", BigInteger.ZERO)); + assertEquals(BigInteger.ZERO, Cast.toBigInteger("0", BigInteger.TEN)); + } + + @Test + void testToBigDecimal() { + assertNull(Cast.toBigDecimal(null, null)); + assertNull(Cast.toBigDecimal("", null)); + assertNull(Cast.toBigDecimal("qwe", null)); + assertEquals(BigDecimal.valueOf(33.1), Cast.toBigDecimal(null, BigDecimal.valueOf(33.1))); + assertEquals(BigDecimal.valueOf(34.1), Cast.toBigDecimal("", BigDecimal.valueOf(34.1))); + assertEquals(BigDecimal.valueOf(35.1), Cast.toBigDecimal("qwe", BigDecimal.valueOf(35.1))); + assertEquals(BigDecimal.valueOf(12.2), Cast.toBigDecimal("12.2", BigDecimal.valueOf(36.1))); + assertEquals(BigDecimal.valueOf(0.2), Cast.toBigDecimal("0.2", BigDecimal.valueOf(37.1))); + assertEquals(BigDecimal.valueOf(0.0), Cast.toBigDecimal("0.0", BigDecimal.valueOf(38.1))); + } + + @Test + void testToEmail() { + assertNull(Cast.toEmail(null, null)); + assertNull(Cast.toEmail("", null)); + assertNull(Cast.toEmail("qwe", null)); + assertEquals("default", Cast.toEmail(null, "default")); + assertEquals("default", Cast.toEmail("", "default")); + assertEquals("default", Cast.toEmail("qwe", "default")); + assertEquals("mail@test.net", Cast.toEmail(" mail@test.net ", "default")); + } + + @Test + void testToDate() { + DateFormat format = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z", Locale.US); + assertNull(Cast.toDate(format, "Wed, Jul 4, '01", null)); + assertEquals(994273736000L, Cast.toDate(format, "2001.07.04 AD at 12:08:56 PDT", null).getTime()); + } + + @Test + void testToEnum() { + assertNull(Cast.toEnum(TestEnum.class, null, null)); + assertNull(Cast.toEnum(TestEnum.class, "", null)); + assertNull(Cast.toEnum(TestEnum.class, "qwe", null)); + assertEquals(TestEnum.three, Cast.toEnum(TestEnum.class, null, TestEnum.three)); + assertEquals(TestEnum.two, Cast.toEnum(TestEnum.class, "", TestEnum.two)); + assertEquals(TestEnum.one, Cast.toEnum(TestEnum.class, "qwe", TestEnum.one)); + assertEquals(TestEnum.zero, Cast.toEnum(TestEnum.class, "zero", TestEnum.one)); + } + + + enum TestEnum {zero, one, two, three} + + +} diff --git a/src/test/java/ua/net/uid/utils/helpers/CommonHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/CommonHelperTest.java new file mode 100644 index 0000000..a2e8b33 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/CommonHelperTest.java @@ -0,0 +1,85 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CommonHelperTest { + + CommonHelperTest() { + } + + @Test + void testClose() { + AutoCloseableImpl closeable = new AutoCloseableImpl(); + CommonHelper.close(closeable); + assertTrue(closeable.called); + } + + @Test + void testIsEmptyCharSequence() { + StringBuilder src = null; + assertTrue(CommonHelper.isEmpty((CharSequence) null)); + src = new StringBuilder(); + assertTrue(CommonHelper.isEmpty(src)); + src.append("test"); + assertFalse(CommonHelper.isEmpty(src)); + } + + @Test + void testIsEmptyString() { + String src = null; + assertTrue(CommonHelper.isEmpty(src)); + src = ""; + assertTrue(CommonHelper.isEmpty(src)); + src = "test"; + assertFalse(CommonHelper.isEmpty(src)); + } + + @Test + void testIsEmptyCollection() { + Collection src = null; + assertTrue(CommonHelper.isEmpty(src)); + src = new ArrayList(); + assertTrue(CommonHelper.isEmpty(src)); + src.add("1"); + assertFalse(CommonHelper.isEmpty(src)); + } + + @Test + void testIsEmptyMap() { + Map src = null; + assertTrue(CommonHelper.isEmpty(src)); + src = new HashMap(); + assertTrue(CommonHelper.isEmpty(src)); + src.put(1, "1"); + assertFalse(CommonHelper.isEmpty(src)); + } + + @Test + void testIsEmptyGenericArray() { + Integer[] src = null; + assertTrue(CommonHelper.isEmpty(src)); + src = new Integer[0]; + assertTrue(CommonHelper.isEmpty(src)); + src = new Integer[]{1}; + assertFalse(CommonHelper.isEmpty(src)); + } + + static class AutoCloseableImpl implements AutoCloseable { + boolean called = false; + + @Override + public void close() throws Exception { + called = true; + throw new IOException("test exception"); + } + } +} diff --git a/src/test/java/ua/net/uid/utils/helpers/EnumHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/EnumHelperTest.java new file mode 100644 index 0000000..daf02b7 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/EnumHelperTest.java @@ -0,0 +1,50 @@ +package ua.net.uid.utils.helpers; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import org.junit.jupiter.api.Test; + +public class EnumHelperTest { + @Test + void testStringToEnumWithDefault() { + assertNull(EnumHelper.valueOf(Source.class, "zero", null)); + assertEquals(Source.four, EnumHelper.valueOf(Source.class, "zero", Source.four)); + assertEquals(Source.one, EnumHelper.valueOf(Source.class, "one", null)); + assertEquals(Source.four, EnumHelper.valueOf(Source.class, "four", null)); + } + + @Test + void testStringToEnumDefaultNull() { + assertNull(EnumHelper.valueOf(Source.class, "zero")); + assertEquals(Source.two, EnumHelper.valueOf(Source.class, "two")); + assertEquals(Source.three, EnumHelper.valueOf(Source.class, "three")); + } + + @Test + void toList() { + assertEquals( + Arrays.asList(Source.one, Source.two, Source.three, Source.four, Source.five), + EnumHelper.toList(Source.class) + ); + } + + @Test + void toMap() { + Map map = new HashMap<>(); + map.put(Source.one.toString(), Source.one); + map.put(Source.two.toString(), Source.two); + map.put(Source.three.toString(), Source.three); + map.put(Source.four.toString(), Source.four); + map.put(Source.five.toString(), Source.five); + + assertEquals(map, EnumHelper.toMap(Source.class)); + } + + enum Source { + one, two, three, four, five + } +} + diff --git a/src/test/java/ua/net/uid/utils/helpers/NumberHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/NumberHelperTest.java new file mode 100644 index 0000000..e68b59e --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/NumberHelperTest.java @@ -0,0 +1,24 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class NumberHelperTest { + private final long LONG_VALUE = 0x12345678a1b2c3d4L; + private final byte[] BYTE_ARRAY = {(byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0xa1, (byte) 0xb2, (byte) 0xc3, (byte) 0xd4}; + + NumberHelperTest() { + } + + @Test + void testLongToBytes() { + assertArrayEquals(BYTE_ARRAY, NumberHelper.longToBytes(LONG_VALUE)); + } + + @Test + void testBytesToLong() { + assertEquals(LONG_VALUE, NumberHelper.bytesToLong(BYTE_ARRAY)); + } +} diff --git a/src/test/java/ua/net/uid/utils/helpers/RandomHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/RandomHelperTest.java new file mode 100644 index 0000000..751878c --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/RandomHelperTest.java @@ -0,0 +1,55 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class RandomHelperTest { //TODO RandomHelperTest + + RandomHelperTest() { + } + + @Test + void testRandomCharsWithLimitLength() { + int minLength = 20; + int maxLength = 50; + char[] result = RandomHelper.randomChars(minLength, maxLength); + assertNotNull(result); + assertTrue(result.length >= minLength); + assertTrue(result.length <= maxLength); + } + + @Test + void testRandomCharsWithLimitLengthAndCustomRandom() { + int minLength = 20; + int maxLength = 50; + Random random = new Random(); + char[] result = RandomHelper.randomChars(minLength, maxLength, random); + assertNotNull(result); + assertTrue(result.length >= minLength); + assertTrue(result.length <= maxLength); + } + + @Test + void testRandomStringWithLimitLength() { + int minLength = 2; + int maxLength = 5; + String result = RandomHelper.randomString(minLength, maxLength); + assertNotNull(result); + assertTrue(result.length() >= minLength); + assertTrue(result.length() <= maxLength); + } + + @Test + void testRandomStringWithLimitLengthAndCustomRandom() { + int minLength = 2; + int maxLength = 5; + Random random = new Random(); + String result = RandomHelper.randomString(minLength, maxLength, random); + assertTrue(result.length() >= minLength); + assertTrue(result.length() <= maxLength); + } +} diff --git a/src/test/java/ua/net/uid/utils/helpers/RegexHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/RegexHelperTest.java new file mode 100644 index 0000000..bf65a04 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/RegexHelperTest.java @@ -0,0 +1,43 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import java.util.Set; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertTrue; + + +class RegexHelperTest { + @Test + void testGetNamedGroups() { + Pattern pattern = Pattern.compile("(.+)@(?[^@]+(\\.)(?[^.@]+))"); + Set result = RegexHelper.getNamedGroupsSet(pattern); + assertTrue(result.contains("host")); + assertTrue(result.contains("zone")); + } + + /* + @Test + void testGetNamedGroups() { + Pattern pattern = Pattern.compile("(.+)@(?[^@]+(\\.)(?[^.@]+))"); + Map result = RegexHelper.getNamedGroups(pattern); + assertEquals((Integer) 2, result.get("host")); + assertEquals((Integer) 4, result.get("zone")); + } + + @Test + void testGetGroupsByName() { + Pattern pattern = Pattern.compile("^(.+)@(?([^@]+\\.)?(?[^.@]+))$"); + Map groupsMap = RegexHelper.getNamedGroups(pattern); + Set groups = groupsMap.keySet(); + Matcher matcher = pattern.matcher("nobody@test.mail.com"); + assertTrue(matcher.matches()); + Map result = RegexHelper.getGroupsByName(matcher, groups); + assertEquals("test.mail.com", matcher.group(groupsMap.get("host"))); + assertEquals("test.mail.com", result.get("host")); + assertEquals("com", matcher.group(groupsMap.get("zone"))); + assertEquals("com", result.get("zone")); + } + */ +} diff --git a/src/test/java/ua/net/uid/utils/helpers/StringHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/StringHelperTest.java new file mode 100644 index 0000000..4ac9e70 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/StringHelperTest.java @@ -0,0 +1,102 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +@SuppressWarnings("SpellCheckingInspection") +class StringHelperTest { + + @Test + void testByteArrayAsHexToCharArray() { + byte[] src = new byte[256]; + for (int i = 0; i < 256; ++i) { + src[i] = (byte) i; + } + char[] dst = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff".toCharArray(); + char[] result = StringHelper.toHex(src); + assertArrayEquals(dst, result); + } + + @Test + void testByteArrayAsHexToAppendable() throws Exception { + byte[] src = new byte[256]; + for (int i = 0; i < 256; ++i) { + src[i] = (byte) i; + } + String dst = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + Appendable builder = new StringBuilder(); + StringHelper.toHex(builder, src); + assertEquals(dst, builder.toString()); + } + + @Test + void testEscapeToAppendableWithRange() throws Exception { + String src = "a\nsd`!@#$%^&*()\u0001\"'\n\r\\\t\b\fsdfцыувфыв\u0017"; + String dst = "d`!@#$%^&*()\\u0001\\\"'\\n\\r\\\\\\t\\b\\fsdfцыувф"; + Appendable builder = new StringBuilder(); + StringHelper.escape(builder, src, 3, src.length() - 3); + assertEquals(dst, builder.toString()); + } + + @Test + void testEscapeToAppendable() throws Exception { + String src = "asd`!@#$%^&*()\u0001\"'\n\r\\\t\b\fsdfцыувфыв\u0017"; + String dst = "asd`!@#$%^&*()\\u0001\\\"'\\n\\r\\\\\\t\\b\\fsdfцыувфыв\\u0017"; + Appendable builder = new StringBuilder(); + StringHelper.escape(builder, src); + assertEquals(dst, builder.toString()); + } + + @Test + void testEscapeToString() { + String src = "asd`!@#$%^&*()\u0001\"'\n\r\\\t\b\fsdfцыувфыв\u0017"; + String dst = "asd`!@#$%^&*()\\u0001\\\"'\\n\\r\\\\\\t\\b\\fsdfцыувфыв\\u0017"; + assertEquals(dst, StringHelper.escape(src)); + } + + @Test + void testUnescapeToAppendable() throws Exception { + String src = "asd`!@#$%^&*()\\u0001\\\"'\\n\\r\\\\\\t\\b\\fsdfцыувфыв\\u0017"; + String dst = "asd`!@#$%^&*()\u0001\"'\n\r\\\t\b\fsdfцыувфыв\u0017"; + Appendable builder = new StringBuilder(); + StringHelper.unescape(builder, src); + assertEquals(dst, builder.toString()); + } + + @Test + void testUnescapeToString() { + String src = "asd`!@#$%^&*()\\u0001\\\"'\\n\\r\\\\\\t\\b\\fsdfцыувфыв\\u0017"; + String dst = "asd`!@#$%^&*()\u0001\"'\n\r\\\t\b\fsdfцыувфыв\u0017"; + assertEquals(dst, StringHelper.unescape(src)); + } + + @Test + void testTrimStringNotThrowNPE() { + assertNull(StringHelper.trim(null)); + assertEquals("abc", StringHelper.trim("\t abc\r\n")); + } + + @Test + void testLtrimStringNotThrowNPE() { + assertNull(StringHelper.trim(null)); + assertEquals("abc\r\n", StringHelper.ltrim("\t abc\r\n")); + } + + @Test + void testRtrimStringNotThrowNPE() { + assertNull(StringHelper.trim(null)); + assertEquals("\t abc", StringHelper.rtrim("\t abc\r\n")); + } + + @Test + void testSkipWhitespaceTest() { + String src = "asd qwe\t\n123\f\f\fzzz "; + assertEquals(0, StringHelper.skipWhitespace(src, 0)); + assertEquals(4, StringHelper.skipWhitespace(src, 3)); + assertEquals(9, StringHelper.skipWhitespace(src, 7)); + assertEquals(15, StringHelper.skipWhitespace(src, 12)); + assertEquals(15, StringHelper.skipWhitespace(src, 15)); + assertEquals(src.length(), StringHelper.skipWhitespace(src, 18)); + } +} diff --git a/src/test/java/ua/net/uid/utils/helpers/TransliterateTest.java b/src/test/java/ua/net/uid/utils/helpers/TransliterateTest.java new file mode 100644 index 0000000..fda62ce --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/TransliterateTest.java @@ -0,0 +1,25 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class TransliterateTest { + @Test + void testTransliterateFromCharSequenceToStringBuilder() { + StringBuilder builder = new StringBuilder(); + String test = "Сжатие SSL/TLS было запрещено по умолчанию ©"; + Transliterate.transliterate(builder, test); + //noinspection SpellCheckingInspection + assertEquals("Szhatie SSL/TLS bylo zapresheno po umolchaniyu (c)", builder.toString()); + } + + @Test + void testTransliterateFromCharSequence() { + StringBuilder builder = new StringBuilder(); + String test = "Сжатие SSL/TLS было запрещено по умолчанию"; + Transliterate.transliterate(builder, test); + //noinspection SpellCheckingInspection + assertEquals("Szhatie SSL/TLS bylo zapresheno po umolchaniyu", Transliterate.transliterate(test).toString()); + } +} diff --git a/src/test/java/ua/net/uid/utils/helpers/XmlHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/XmlHelperTest.java new file mode 100644 index 0000000..5c27a1f --- /dev/null +++ b/src/test/java/ua/net/uid/utils/helpers/XmlHelperTest.java @@ -0,0 +1,46 @@ +package ua.net.uid.utils.helpers; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class XmlHelperTest { + @SuppressWarnings("SpellCheckingInspection") + private static final String src = " &< &-amp; <-lt; >-gt; \"-quot; '-#39; >& "; + + @Test + void testEscapeXmlEntitiesByRangeToAppendable() throws Exception { + StringBuilder builder = new StringBuilder(); + XmlHelper.escape(builder, src, 4, src.length() - 4); + assertEquals( + "&-amp; <-lt; >-gt; "-quot; '-#39;", + builder.toString() + ); + } + + @Test + void testEscapeXmlEntitiesToAppendable() throws Exception { + StringBuilder builder = new StringBuilder(); + XmlHelper.escape(builder, src); + assertEquals( + " &< &-amp; <-lt; >-gt; "-quot; '-#39; >& ", + builder.toString() + ); + } + + @Test + void testEscapeXmlEntitiesByRangeToString() { + assertEquals( + "&-amp; <-lt; >-gt; "-quot; '-#39;", + XmlHelper.escape(src, 4, src.length() - 4) + ); + } + + @Test + void testEscapeXmlEntitiesToString() { + assertEquals( + " &< &-amp; <-lt; >-gt; "-quot; '-#39; >& ", + XmlHelper.escape(src) + ); + } +} diff --git a/src/test/java/ua/net/uid/utils/io/ExpiringCacheTest.java b/src/test/java/ua/net/uid/utils/io/ExpiringCacheTest.java new file mode 100644 index 0000000..3002b9f --- /dev/null +++ b/src/test/java/ua/net/uid/utils/io/ExpiringCacheTest.java @@ -0,0 +1,89 @@ +package ua.net.uid.utils.io; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +//TODO ExpiringCacheTest +class ExpiringCacheTest { + + @Test + void future() { + } + + @Test + void future1() { + } + + @Test + void future2() { + } + + @Test + void future3() { + } + + @Test + void get() { + } + + @Test + void get1() { + } + + @Test + void get2() { + } + + @Test + void get3() { + } + + @Test + void set() { + } + + @Test + void set1() { + } + + @Test + void set2() { + } + + @Test + void put() { + } + + @Test + void put1() { + } + + @Test + void put2() { + } + + @Test + void extractFuture() { + } + + @Test + void extract() { + } + + @Test + void remove() { + } + + @Test + void clear() { + } + + @Test + void count() { + } + + @Test + void gc() { + } +} \ No newline at end of file diff --git a/src/test/java/ua/net/uid/utils/io/LocalCacheTest.java b/src/test/java/ua/net/uid/utils/io/LocalCacheTest.java new file mode 100644 index 0000000..2cfef8b --- /dev/null +++ b/src/test/java/ua/net/uid/utils/io/LocalCacheTest.java @@ -0,0 +1,109 @@ +package ua.net.uid.utils.io; + +import org.junit.jupiter.api.Test; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import static org.junit.jupiter.api.Assertions.*; + +@SuppressWarnings("unchecked") +class LocalCacheTest { + + @Test + void testFuture_GenericType() throws InterruptedException, ExecutionException { + LocalCache instance = new LocalCache(); + instance.set("test", 123); + Future result = instance.future("test"); + assertNotNull(result); + assertEquals(123, result.get()); + } + + @Test + void testFuture_GenericType_Callable() throws InterruptedException, ExecutionException { + LocalCache instance = new LocalCache(); + Future result = instance.future("test", () -> 456); + assertNotNull(result); + assertEquals(456, result.get()); + } + + @Test + void testGet_GenericType() { + LocalCache instance = new LocalCache(); + instance.set("test", 789); + Object result = instance.get("test"); + assertNotNull(result); + assertEquals(789, result); + } + + @Test + void testGet_GenericType_Callable() { + LocalCache instance = new LocalCache(); + Object result = instance.get("test", () -> 65535); + assertNotNull(result); + assertEquals(65535, result); + } + + @Test + void testSet_GenericType_GenericType() throws InterruptedException, ExecutionException { + LocalCache instance = new LocalCache(); + instance.set("test", 2345); + Future result = instance.future("test"); + assertNotNull(result); + assertEquals(2345, result.get()); + } + + @Test + void testSet_GenericType_Callable() throws InterruptedException, ExecutionException { + LocalCache instance = new LocalCache(); + instance.put("testSet_GenericType_Callable", () -> "testSet_GenericType_Callable"); + Future result = instance.future("testSet_GenericType_Callable"); + assertNotNull(result); + assertEquals("testSet_GenericType_Callable", result.get()); + } + + @Test + void testExtractFuture() throws InterruptedException, ExecutionException { + LocalCache instance = new LocalCache(); + instance.put("testExtractFuture", () -> "testExtractFuture"); + Future result = instance.extractFuture("testExtractFuture"); + assertNotNull(result); + assertNull(instance.future("testExtractFuture")); + assertEquals("testExtractFuture", result.get()); + } + + @Test + void testExtract() { + LocalCache instance = new LocalCache(); + instance.put("testExtract", () -> "testExtract"); + Object result = instance.extract("testExtract"); + assertNotNull(result); + assertNull(instance.future("testExtract")); + assertEquals("testExtract", result); + } + + @Test + void testRemove() { + LocalCache instance = new LocalCache(); + instance.put("testRemove", () -> "testRemove"); + instance.remove("testExtract"); + assertNull(instance.future("testExtract")); + } + + @Test + void testClear() { + LocalCache instance = new LocalCache(); + instance.put("testClear", () -> "testClear"); + instance.clear(); + assertNull(instance.future("testClear")); + } + + @Test + void testCount() { + LocalCache instance = new LocalCache(); + instance.set(0, 0); + instance.set(1, 1); + instance.set(2, 2); + assertEquals(3, instance.count()); + } +} diff --git a/src/test/java/ua/net/uid/utils/io/SimpleWriterTest.java b/src/test/java/ua/net/uid/utils/io/SimpleWriterTest.java new file mode 100644 index 0000000..cd3bb91 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/io/SimpleWriterTest.java @@ -0,0 +1,134 @@ +package ua.net.uid.utils.io; + +import org.junit.jupiter.api.Test; + +import java.io.Writer; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class SimpleWriterTest { + + @Test + void testWriteChar() { + SimpleWriter instance = new SimpleWriter(); + instance.write(32); + assertEquals(" ", instance.toString()); + } + + @Test + void testWriteCharsFromOffsetWithLength() { + char[] buf = "aaa0123456789bbb".toCharArray(); + SimpleWriter instance = new SimpleWriter(); + instance.write(buf, 3, 10); + assertEquals("0123456789", instance.toString()); + } + + @Test + void testWriteString() { + String str = "prototype"; + SimpleWriter instance = new SimpleWriter(); + instance.write(str); + assertEquals(str, instance.toString()); + } + + @Test + void testWriteStringFromOffsetWithLength() { + String buf = "aaa0123456789bbb"; + SimpleWriter instance = new SimpleWriter(); + instance.write(buf, 3, 10); + assertEquals("0123456789", instance.toString()); + } + + @Test + void testAppendCharSequence() { + SimpleWriter instance = new SimpleWriter(); + Writer result = instance.append("test"); + assertEquals(result, instance); + assertEquals("test", result.toString()); + } + + @Test + void testAppendCharSequenceFromOffsetWithLength() { + CharSequence data = "aaa0123456789bbb"; + SimpleWriter instance = new SimpleWriter(); + Writer result = instance.append(data, 3, 10); + assertEquals(result, instance); + assertEquals("0123456", result.toString()); + } + + @Test + void testAppendChar() { + SimpleWriter instance = new SimpleWriter(); + Writer result = instance.append(' '); + assertEquals(result, instance); + assertEquals(" ", instance.toString()); + } + + @Test + void testFlush() { + SimpleWriter instance = new SimpleWriter(); + instance.write("The test case is a prototype."); + instance.flush(); + assertEquals("The test case is a prototype.", instance.toString()); + } + + @Test + void testClose() { + SimpleWriter instance = new SimpleWriter(); + instance.write("The test case is a prototype."); + instance.close(); + assertEquals("The test case is a prototype.", instance.toString()); + } + + @Test + void testLength() { + String data = "aaa0123456789bbb"; + SimpleWriter instance = new SimpleWriter(); + instance.write(data); + assertEquals(data.length(), instance.length()); + } + + @Test + void testCharAt() { + String data = "aaa0123456789bbb"; + SimpleWriter instance = new SimpleWriter(); + instance.write(data); + assertEquals(data.charAt(3), instance.charAt(3)); + } + + @Test + void testSubSequence() { + String data = "aaa0123456789bbb"; + SimpleWriter instance = new SimpleWriter(); + instance.write(data); + assertEquals("0123456", instance.subSequence(3, 10)); + } + + @Test + void testToString() { + String data = "aaa0123456789bbb"; + SimpleWriter instance = new SimpleWriter(); + instance.write(data); + assertEquals(data, instance.toString()); + } + + @Test + void testGetBuilder() { + String data = "aaa0123456789bbb"; + SimpleWriter instance = new SimpleWriter(); + instance.write(data); + StringBuilder result = instance.getBuilder(); + assertEquals(data, result.toString()); + } + + @Test + void testToCharArray() { + char[] data = "aaa0123456789bbb".toCharArray(); + SimpleWriter instance = new SimpleWriter(); + instance.write(data); + char[] result = instance.toCharArray(); + assertArrayEquals(data, result); + } + +} diff --git a/src/test/java/ua/net/uid/utils/iterators/AbstractFilteredIteratorTest.java b/src/test/java/ua/net/uid/utils/iterators/AbstractFilteredIteratorTest.java new file mode 100644 index 0000000..e69baf2 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/iterators/AbstractFilteredIteratorTest.java @@ -0,0 +1,76 @@ +package ua.net.uid.utils.iterators; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class AbstractFilteredIteratorTest { + private final List source = Arrays.asList(1, "q", 3.14, null, "w", true, "r", 4); + + @Test + void simpleIterateTest() { + Iterator it = new StringFilteredIterator(source.iterator()); + assertTrue(it.hasNext()); + assertEquals("q", it.next()); + assertTrue(it.hasNext()); + assertEquals("w", it.next()); + assertTrue(it.hasNext()); + assertEquals("r", it.next()); + assertFalse(it.hasNext()); + } + + @Test + void removeElementTest() { + List items = new ArrayList<>(source); + + { + Iterator it = new StringFilteredIterator(items.iterator()); + assertTrue(it.hasNext()); + assertEquals("q", it.next()); + assertTrue(it.hasNext()); + assertEquals("w", it.next()); + assertTrue(it.hasNext()); + assertEquals("r", it.next()); + it.remove(); + assertFalse(it.hasNext()); + } + + assertArrayEquals(new Object[]{1, "q", 3.14, null, "w", true, 4}, items.toArray()); + + { + Iterator it = new StringFilteredIterator(items.iterator()); + assertTrue(it.hasNext()); + try { + it.remove(); + assertFalse(true); + } catch (IllegalStateException ex) { + assertNotNull(ex); + } + assertTrue(it.hasNext()); + assertEquals("q", it.next()); + it.remove(); + assertTrue(it.hasNext()); + assertEquals("w", it.next()); + it.remove(); + assertFalse(it.hasNext()); + } + assertArrayEquals(new Object[]{1, 3.14, null, true, 4}, items.toArray()); + + } + + private final static class StringFilteredIterator extends AbstractFilteredIterator { + StringFilteredIterator(Iterator iterator) { + super(iterator); + } + + @Override + protected boolean check(Object item) { + return item instanceof String; + } + } +} \ No newline at end of file diff --git a/src/test/java/ua/net/uid/utils/iterators/AbstractTransformIteratorTest.java b/src/test/java/ua/net/uid/utils/iterators/AbstractTransformIteratorTest.java new file mode 100644 index 0000000..cd1b955 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/iterators/AbstractTransformIteratorTest.java @@ -0,0 +1,62 @@ +package ua.net.uid.utils.iterators; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class AbstractTransformIteratorTest { + private final List source = Arrays.asList(1, 2, 3); + + @Test + void simpleIterateTest() { + Iterator it = new IntToStringIterator(source.iterator()); + assertTrue(it.hasNext()); + assertEquals("1", it.next()); + assertTrue(it.hasNext()); + assertEquals("2", it.next()); + assertTrue(it.hasNext()); + assertEquals("3", it.next()); + assertFalse(it.hasNext()); + try { + it.next(); + assertFalse(true); + } catch (Exception ex) { + assertNotNull(ex); + } + } + + @Test + void removeItemTest() { + List list = new ArrayList<>(source); + Iterator it = new IntToStringIterator(list.iterator()); + assertTrue(it.hasNext()); + assertEquals("1", it.next()); + it.remove(); + assertEquals(2, list.size()); + assertTrue(it.hasNext()); + assertEquals("2", it.next()); + it.remove(); + assertEquals(1, list.size()); + assertTrue(it.hasNext()); + assertEquals("3", it.next()); + it.remove(); + assertTrue(list.isEmpty()); + assertFalse(it.hasNext()); + } + + private static final class IntToStringIterator extends AbstractTransformIterator { + IntToStringIterator(Iterator iterator) { + super(iterator); + } + + @Override + protected String transform(Integer source) { + return String.valueOf(source); + } + } +} \ No newline at end of file diff --git a/src/test/java/ua/net/uid/utils/iterators/ArrayIteratorTest.java b/src/test/java/ua/net/uid/utils/iterators/ArrayIteratorTest.java new file mode 100644 index 0000000..544908c --- /dev/null +++ b/src/test/java/ua/net/uid/utils/iterators/ArrayIteratorTest.java @@ -0,0 +1,25 @@ +package ua.net.uid.utils.iterators; + +import java.util.Iterator; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class ArrayIteratorTest { + @Test + void simpleIterateTest() { + Iterator it = new ArrayIterator<>(new Integer[]{1, 2, 3}); + assertTrue(it.hasNext()); + assertEquals(Integer.valueOf(1), it.next()); + assertTrue(it.hasNext()); + assertEquals(Integer.valueOf(2), it.next()); + assertTrue(it.hasNext()); + assertEquals(Integer.valueOf(3), it.next()); + assertFalse(it.hasNext()); + try { + it.next(); + assertFalse(true); + } catch (Exception ex) { + assertNotNull(ex); + } + } +} diff --git a/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java b/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java new file mode 100644 index 0000000..05920f9 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java @@ -0,0 +1,92 @@ +package ua.net.uid.utils.tools; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import static ua.net.uid.utils.tools.DailyEquation.*; + +/** + * + * @author nightfall + */ +public class DailyEquationTest { + private static final SimpleDateFormat DATE_FORMAT_DAY = new SimpleDateFormat("yyyyMMdd"); + private static final SimpleDateFormat DATE_FORMAT_MINUTES = new SimpleDateFormat("yyyyMMdd HH:mm"); + + @Test + public void testCalculateEvent() { + //https://edwilliams.org/sunrise_sunset_example.htm + assertEquals(9.441, DailyEquation.calculateEvent(40.9, -74.3 / 15, Zenith.OFFICIAL.getDegrees(), 176, true), 0.001); + } + + @Test + public void testGetSunEvents() throws ParseException { + //https://edwilliams.org/sunrise_sunset_example.htm + assertEvents("America/New_York", "19900625", 40.9, -74.3, "05:26", "20:33"); // June 25, 1990 / Wayne, NJ + + //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetTest.java + assertEvents("PST", "20130120", 34.0522, -118.2437, "06:56", "17:11"); + assertEvents("CET", "20130120", 48.8567, 2.351, "08:35", "17:28"); + assertEvents("Australia/Sydney", "20121225", -33.86, 151.2111, "05:43", "20:07"); + assertEvents("Japan", "20130501", 35.6938, 139.7036, "04:50", "18:27"); + assertEvents("Europe/Dublin", "20130605", 53.3441, -6.2675, "05:00", "21:46"); + assertEvents("CST", "20130622", 41.8781, -87.6298, "05:15", "20:29"); + assertEvents("Pacific/Honolulu", "20150827", 21.3069, -157.8583, "06:13", "18:51"); + assertEvents("America/Argentina/Buenos_Aires", "20130501", -34.6092, -58.3732, "07:29", "18:11"); + assertEvents("America/Argentina/Buenos_Aires", "20131019", -34.6092, -58.3732, "06:06", "19:10"); + + assertEvents("America/Argentina/Buenos_Aires", "20130126", -34.6092, -58.3732, "06:07", "20:04"); + assertEvents("America/Argentina/Buenos_Aires", "20131020", -34.6092, -58.3732, "06:05", "19:11"); + assertEvents("America/Argentina/Buenos_Aires", "20131031", -34.6092, -58.3732, "05:53", "19:21"); + + assertEvents("Antarctica/McMurdo", "20150419", -77.8456, 166.6693, "10:34", "15:04"); // "10:37", "15:08" + assertEvents("Antarctica/McMurdo", "20150621", -77.8456, 166.6693, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); + assertEvents("Antarctica/McMurdo", "20150921", -77.8456, 166.6693, "06:49", "18:47"); + assertEvents("Antarctica/McMurdo", "20151221", -77.8456, 166.6693, Zenith.OFFICIAL, Type.POLAR_DAY, null, null); + + //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetSpecificLocationsTest.java + assertEvents("EST", "20160228", 82.50178, -62.34809, "10:13", "12:47"); // "10:27", "12:19 + assertEvents("EST", "20160228", 82.5018, -62.3481, "10:13", "12:47"); // "10:27", "12:19" + assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:17", "12:31" + assertEvents("EST", "20160228", 82.501667, -62.348056, "10:13", "12:47"); // "10:15", "12:32" + assertEvents("EST", "20160228", 82.5, -62.35, "10:13", "12:48"); // "10:14", "12:33" + assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:14", "12:33" + + assertEvents("Europe/Kiev", "20190708", 50.401984, 30.531065, "04:55", "21:09" ); + assertEvents("Asia/Kamchatka", "20190706", 53.047252, 158.628714, "05:07", "21:52"); + + assertEvents("America/Moscow", "20181201", 69.000779, 33.116392, "09:14", "09:44"); // Мурманск - https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D1%8F%D1%80%D0%BD%D0%B0%D1%8F_%D0%BD%D0%BE%D1%87%D1%8C + assertEvents("America/Moscow", "20181202", 69.000779, 33.116392, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); + assertEvents("America/Moscow", "20190111", 69.000779, 33.116392, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); + assertEvents("America/Moscow", "20190112", 69.000779, 33.116392, "09:29", "10:29"); + + assertEvents("Atlantic/Reykjavik", "20190708", 65.67, -18.1, "02:26", "00:06"); // Акюрейри, Регион Нордюрланд-Эйстра, Исландия + + } + + private void assertEvents(String timezone, String date, double lat, double lon, String sr, String ss) throws ParseException { + assertEvents(timezone, date, lat, lon, Zenith.OFFICIAL, Type.NORMAL_DAY, sr, ss); + } + private void assertEvents(String timezone, String date, double lat, double lon, Zenith zenith, Type type, String sr, String ss) throws ParseException { + TimeZone tz = TimeZone.getTimeZone(timezone); + + SimpleDateFormat parse = (SimpleDateFormat) DATE_FORMAT_DAY.clone(); + parse.setTimeZone(tz); + + Calendar calendar = Calendar.getInstance(tz); + calendar.setTime(parse.parse(date)); + + Events events = DailyEquation.getSunEvents(lat, lon, calendar, zenith); + + assertSame(type, events.getType()); + if (type == Type.NORMAL_DAY) { + SimpleDateFormat format = (SimpleDateFormat) DATE_FORMAT_MINUTES.clone(); + format.setTimeZone(tz); + assertEquals(date + ' ' + sr, format.format(events.getSunrise())); + assertEquals(date + ' ' + ss, format.format(events.getSunset())); + } + } +} diff --git a/src/test/java/ua/net/uid/utils/tools/MaskTest.java b/src/test/java/ua/net/uid/utils/tools/MaskTest.java new file mode 100644 index 0000000..e9036f3 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/tools/MaskTest.java @@ -0,0 +1,10 @@ +package ua.net.uid.utils.tools; + +import org.junit.jupiter.api.Test; + +class MaskTest { + @Test + void matchTest() { + //TODO MaskTest::matchTest() + } +} \ No newline at end of file