From 4b1a834883dce0ae226078dddb98f9819810b618 Mon Sep 17 00:00:00 2001 From: AKurakin Date: Mon, 1 Jul 2024 14:36:31 +0300 Subject: [PATCH] =?UTF-8?q?dictionaries.xml=20(data.sql)=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20LICC,=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=BB=20=D1=8E=D0=BD=D0=B8=D1=82=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clearing-parent/backend-api/pom.xml | 5 + .../src/main/resources/meta/dictionaries.xml | 4 +- .../src/main/resources/meta/meta.xml | 20 +- .../clearing/backendapi/meta/DataXmlTest.java | 175 ++++++++++++++++++ .../src/main/resources/db/DICTIONARIES.sql | 4 +- 5 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 clearing-parent/backend-api/src/test/java/ru/spcex/clearing/backendapi/meta/DataXmlTest.java diff --git a/clearing-parent/backend-api/pom.xml b/clearing-parent/backend-api/pom.xml index 5e9d02c10..bab1e7850 100644 --- a/clearing-parent/backend-api/pom.xml +++ b/clearing-parent/backend-api/pom.xml @@ -112,6 +112,11 @@ org.mockito mockito-core + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + test + diff --git a/clearing-parent/backend-api/src/main/resources/meta/dictionaries.xml b/clearing-parent/backend-api/src/main/resources/meta/dictionaries.xml index 5f04c6b6d..d3148ff2e 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/dictionaries.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/dictionaries.xml @@ -62,7 +62,7 @@ - + @@ -76,7 +76,7 @@ - + diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.xml b/clearing-parent/backend-api/src/main/resources/meta/meta.xml index 25d069830..f9c3ba5c8 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.xml @@ -1,6 +1,6 @@ - + @@ -920,7 +920,7 @@ - + @@ -1498,7 +1498,7 @@ - + @@ -1537,7 +1537,7 @@ - + @@ -1565,7 +1565,7 @@ - + @@ -1658,8 +1658,8 @@ - - + + @@ -1695,8 +1695,8 @@ - - + + @@ -1765,7 +1765,7 @@ - + diff --git a/clearing-parent/backend-api/src/test/java/ru/spcex/clearing/backendapi/meta/DataXmlTest.java b/clearing-parent/backend-api/src/test/java/ru/spcex/clearing/backendapi/meta/DataXmlTest.java new file mode 100644 index 000000000..bb299c3de --- /dev/null +++ b/clearing-parent/backend-api/src/test/java/ru/spcex/clearing/backendapi/meta/DataXmlTest.java @@ -0,0 +1,175 @@ +package ru.spcex.clearing.backendapi.meta; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * Проверяет словари на опечатки: пустые значения, сочетание кириллицы и латиницы в одном слове. + * dictionaries.xml + * data_initial.xml + * data_register_code.xml + */ +public class DataXmlTest { + private Logger log = LoggerFactory.getLogger(getClass()); + + @Test + public void testMetaXml() throws IOException { + verifyXML(new File("src/main/resources/meta/meta.xml")); + } + + /** + * Проверка XML (data.xml aka dictionaries.xml) + * + * @throws IOException + */ + @Test + public void testDictionariesXml() throws IOException { + verifyXML(new File("src/main/resources/meta/dictionaries.xml")); + } + + @Test + public void testDataInitialXml() throws IOException { + verifyXML(new File("src/main/resources/meta/data_initial.xml")); + } + + @Test + public void testDataRegisterCodeXml() throws IOException { + verifyXML(new File("src/main/resources/meta/data_register_code.xml")); + } + + protected void verifyXML(File xmlFile) throws IOException { + XmlMapper xmlObjectMapper = new XmlMapper(); + xmlObjectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); + xmlObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // Это юнит-тест с внутренними данными, парсинг DTD выключать не обязательно. + Map root = xmlObjectMapper.readValue(xmlFile, Map.class); + Assertions.assertNotNull(root, "Empty XML in file " + xmlFile); + + String errors = verifyNode(xmlFile.getName(), root); + Assertions.assertNull(errors, errors); + } + + private String verifyNode(String path, Map node) { + for (Map.Entry item : node.entrySet()) { + String name = item.getKey(); + if (!verifyText(name)) { + return path + "> node name \"" + name + "\" has error"; + } + String thisPath = path + "/" + name; + if (item.getValue() instanceof Map itemValue) { + String error = verifyNode(thisPath, itemValue); + if (error != null) + return error; + } else if (item.getValue() instanceof String text) { + if (!verifyText(text)) { + return thisPath + "> has error in content: \"" + text + "\""; + } + } else if (item.getValue() instanceof List values) { + for (Object o : values) { + if (o instanceof Map itemMap) { + String error = verifyNode(thisPath, itemMap); + if (error != null) + return error; + } else if (o instanceof String oVal) { + if (!verifyText(oVal)) { + return thisPath + "> one of values in node \"" + oVal + "\" has error"; + } + } else if (o == null) { + // nothing + } else { + throw new IllegalArgumentException(thisPath + "> Unsupported one of value type " + o.getClass().getSimpleName() + " for verification"); + } + } + } else if (item.getValue() == null) { + // nothing + } else { + throw new IllegalArgumentException(thisPath + "> Unsupported value type " + item.getValue().getClass().getSimpleName() + " for verification"); + } + } + return null; + } + + final char[] CYRILLICS; + final char[] LATINS; + + { + CYRILLICS = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя".toCharArray(); + LATINS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); + Arrays.sort(CYRILLICS); + Arrays.sort(LATINS); + } + + /** + * Проверяет смесь кириллицы и латиницы в одном слове + * + * @param text + * @return + */ + boolean verifyText(String text) { + boolean word = false, cyrillic = false, latin = false; + if (text != null) { + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + boolean isWhitespace = Character.isWhitespace(c); + boolean isCyrillic = Arrays.binarySearch(CYRILLICS, c) >= 0; + boolean isLatin = Arrays.binarySearch(LATINS, c) >= 0; + assert !(isCyrillic && isLatin); + assert !(isWhitespace && (isCyrillic || isLatin)); + if (word && isWhitespace) { + word = false; // слово закончилось + if (cyrillic && latin) + return false; // Смесь кириллицы и латиницы + } else if (!word && !isWhitespace) { + word = true; // новое слово + cyrillic = latin = false; + } + cyrillic |= isCyrillic; + latin |= isLatin; + } + if (cyrillic && latin) + return false; // Смесь кириллицы и латиницы + } + return true; + } + + @Test + public void selfTest() { + verifyText(null); + Assertions.assertTrue(verifyText("")); + Assertions.assertTrue(verifyText("A")); + Assertions.assertTrue(verifyText(" A ")); + Assertions.assertTrue(verifyText("A call of")); + Assertions.assertTrue(verifyText("The spring of spin winter.")); + Assertions.assertTrue(verifyText("Пользователь user текст обычный.")); + Assertions.assertTrue(verifyText("АККаунт mixED 102E333C")); + Assertions.assertTrue(verifyText("АКК_аунт mi_xED 10-+*/2E333C")); + Assertions.assertTrue(verifyText("XML")); + Assertions.assertTrue(verifyText("Same sample apple")); + Assertions.assertTrue(verifyText("По tExT кРАям")); + + Assertions.assertFalse(verifyText("Пользоватьель userтекст обычный.")); + Assertions.assertFalse(verifyText("ХML")); + Assertions.assertFalse(verifyText("XМL")); + Assertions.assertFalse(verifyText("XMЛ")); + Assertions.assertFalse(verifyText(" ХML")); + Assertions.assertFalse(verifyText(" XМL")); + Assertions.assertFalse(verifyText(" XMЛ")); + Assertions.assertFalse(verifyText("ХML ")); + Assertions.assertFalse(verifyText("XМL ")); + Assertions.assertFalse(verifyText("XMЛ ")); + Assertions.assertFalse(verifyText("12XM_Л34")); + Assertions.assertFalse(verifyText("Same sample аррlе")); + Assertions.assertFalse(verifyText("Same samplе apple")); + Assertions.assertFalse(verifyText("Same sample аpple")); + Assertions.assertFalse(verifyText("client_сode")); + } +} diff --git a/clearing-parent/db-scripts/src/main/resources/db/DICTIONARIES.sql b/clearing-parent/db-scripts/src/main/resources/db/DICTIONARIES.sql index 5a4a31026..f27a74ca1 100644 --- a/clearing-parent/db-scripts/src/main/resources/db/DICTIONARIES.sql +++ b/clearing-parent/db-scripts/src/main/resources/db/DICTIONARIES.sql @@ -126,7 +126,7 @@ INSERT INTO DOCUMENT_TYPE_DICTIONARY(ID, CODE, NAME) values (20, 'LICD', 'Док INSERT INTO DOCUMENT_TYPE_DICTIONARY(ID, CODE, NAME) values (21, 'LICT', 'Документ о лицензии по управлению ЦБ') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; -INSERT INTO DOCUMENT_TYPE_DICTIONARY(ID, CODE, NAME) values (22, 'LICС', 'Документ о лицензии по брокерской деятельности ПФИ (производных финансовых инструментов)') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; +INSERT INTO DOCUMENT_TYPE_DICTIONARY(ID, CODE, NAME) values (22, 'LICC', 'Документ о лицензии по брокерской деятельности ПФИ (производных финансовых инструментов)') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; INSERT INTO DOCUMENT_TYPE_DICTIONARY(ID, CODE, NAME) values (23, 'LICF', 'Документ о лицензии форекс-дилера') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME; @@ -154,7 +154,7 @@ INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (10, 'LI INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (11, 'LICT', 'Номер лицензии по управлению ЦБ', 'Управление ценными бумагами') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME; -INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (12, 'LICС', 'Номер лицензии по брокерской деятельности ПФИ (производных финансовых инструментов)', 'Брокерская деятельность ПФИ') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME; +INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (12, 'LICC', 'Номер лицензии по брокерской деятельности ПФИ (производных финансовых инструментов)', 'Брокерская деятельность ПФИ') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME; INSERT INTO COMPANY_SYMBOL_DICTIONARY(ID, CODE, NAME, SHORTNAME) values (13, 'LICF', 'Номер лицензии форекс-дилера', 'Деятельность форекс-дилера') ON CONFLICT (ID) DO UPDATE SET CODE = EXCLUDED.CODE, NAME = EXCLUDED.NAME, SHORTNAME = EXCLUDED.SHORTNAME;