From caf879dc9fc5f9280faf5c4dd18d4801fcf53563 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Mon, 8 Nov 2021 21:04:45 -0600 Subject: [PATCH] Checkpoint --- .../core/actions/TableMetaDataAction.java | 36 ++ .../core/exceptions/QUserFacingException.java | 29 ++ .../model/actions/TableMetaDataRequest.java | 54 +++ .../model/actions/TableMetaDataResult.java | 36 ++ .../core/modules/QModuleDispatcher.java | 2 +- .../core/modules/mock/MockInsertAction.java | 39 ++ .../backend/core/modules/mock/MockModule.java | 33 ++ .../core/modules/mock/MockQueryAction.java | 51 +++ .../backend/core/utils/CollectionUtils.java | 2 +- .../backend/core/utils/ExceptionUtils.java | 34 ++ .../core/actions/InsertActionTest.java | 38 ++ .../core/actions/MetaDataActionTest.java | 32 ++ .../backend/core/actions/QueryActionTest.java | 29 ++ .../core/actions/TableMetaDataActionTest.java | 51 +++ .../core/instances/QInstanceEnricherTest.java | 66 +++ .../core/modules/QModuleDispatcherTest.java | 44 ++ .../core/utils/CollectionUtilsTest.java | 391 ++++++++++++++++++ .../core/utils/ExceptionUtilsTest.java | 29 ++ .../qqq/backend/core/utils/JsonUtilsTest.java | 18 + .../qqq/backend/core/utils/TestUtils.java | 7 +- 20 files changed, 1013 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/actions/TableMetaDataAction.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/exceptions/QUserFacingException.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/model/actions/TableMetaDataRequest.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/model/actions/TableMetaDataResult.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockInsertAction.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockModule.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockQueryAction.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtils.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/actions/InsertActionTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/actions/MetaDataActionTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/actions/QueryActionTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/actions/TableMetaDataActionTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceEnricherTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/modules/QModuleDispatcherTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/utils/CollectionUtilsTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtilsTest.java diff --git a/src/main/java/com/kingsrook/qqq/backend/core/actions/TableMetaDataAction.java b/src/main/java/com/kingsrook/qqq/backend/core/actions/TableMetaDataAction.java new file mode 100644 index 00000000..88aa7594 --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/actions/TableMetaDataAction.java @@ -0,0 +1,36 @@ +package com.kingsrook.qqq.backend.core.actions; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; +import com.kingsrook.qqq.backend.core.model.actions.TableMetaDataRequest; +import com.kingsrook.qqq.backend.core.model.actions.TableMetaDataResult; +import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class TableMetaDataAction +{ + /******************************************************************************* + ** + *******************************************************************************/ + public TableMetaDataResult execute(TableMetaDataRequest tableMetaDataRequest) throws QException + { + // todo pre-customization - just get to modify the request? + TableMetaDataResult tableMetaDataResult = new TableMetaDataResult(); + + QTableMetaData table = tableMetaDataRequest.getInstance().getTable(tableMetaDataRequest.getTableName()); + if(table == null) + { + throw (new QUserFacingException("Table [" + tableMetaDataRequest.getTableName() + "] was not found.")); + } + tableMetaDataResult.setTable(new QFrontendTableMetaData(table, true)); + + // todo post-customization - can do whatever w/ the result if you want + + return tableMetaDataResult; + } +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/exceptions/QUserFacingException.java b/src/main/java/com/kingsrook/qqq/backend/core/exceptions/QUserFacingException.java new file mode 100644 index 00000000..04836636 --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/exceptions/QUserFacingException.java @@ -0,0 +1,29 @@ +package com.kingsrook.qqq.backend.core.exceptions; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class QUserFacingException extends QException +{ + + + /******************************************************************************* + ** + *******************************************************************************/ + public QUserFacingException(String message) + { + super(message); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QUserFacingException(String message, Throwable cause) + { + super(message, cause); + } + +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/actions/TableMetaDataRequest.java b/src/main/java/com/kingsrook/qqq/backend/core/model/actions/TableMetaDataRequest.java new file mode 100644 index 00000000..a55639a6 --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/actions/TableMetaDataRequest.java @@ -0,0 +1,54 @@ +package com.kingsrook.qqq.backend.core.model.actions; + + +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class TableMetaDataRequest extends AbstractQRequest +{ + private String tableName; + + + + /******************************************************************************* + ** + *******************************************************************************/ + public TableMetaDataRequest() + { + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public TableMetaDataRequest(QInstance instance) + { + super(instance); + } + + + + /******************************************************************************* + ** Getter for tableName + ** + *******************************************************************************/ + public String getTableName() + { + return tableName; + } + + + + /******************************************************************************* + ** Setter for tableName + ** + *******************************************************************************/ + public void setTableName(String tableName) + { + this.tableName = tableName; + } +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/actions/TableMetaDataResult.java b/src/main/java/com/kingsrook/qqq/backend/core/model/actions/TableMetaDataResult.java new file mode 100644 index 00000000..eb58c2ca --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/actions/TableMetaDataResult.java @@ -0,0 +1,36 @@ +package com.kingsrook.qqq.backend.core.model.actions; + + +import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData; + + +/******************************************************************************* + * Result for a metaData action + * + *******************************************************************************/ +public class TableMetaDataResult extends AbstractQResult +{ + QFrontendTableMetaData table; + + + + /******************************************************************************* + ** Getter for table + ** + *******************************************************************************/ + public QFrontendTableMetaData getTable() + { + return table; + } + + + + /******************************************************************************* + ** Setter for table + ** + *******************************************************************************/ + public void setTable(QFrontendTableMetaData table) + { + this.table = table; + } +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/QModuleDispatcher.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/QModuleDispatcher.java index 98e61b12..9a1b026e 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/modules/QModuleDispatcher.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/QModuleDispatcher.java @@ -23,8 +23,8 @@ public class QModuleDispatcher public QModuleDispatcher() { backendTypeToModuleClassNameMap = new HashMap<>(); + backendTypeToModuleClassNameMap.put("mock", "com.kingsrook.qqq.backend.core.modules.mock.MockModule"); backendTypeToModuleClassNameMap.put("rdbms", "com.kingsrook.qqq.backend.module.rdbms.RDBSMModule"); - backendTypeToModuleClassNameMap.put("nosql", "com.kingsrook.qqq.backend.module.nosql.NoSQLModule"); // todo - let user define custom type -> classes } diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockInsertAction.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockInsertAction.java new file mode 100644 index 00000000..4e229a2a --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockInsertAction.java @@ -0,0 +1,39 @@ +package com.kingsrook.qqq.backend.core.modules.mock; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.InsertRequest; +import com.kingsrook.qqq.backend.core.model.actions.InsertResult; +import com.kingsrook.qqq.backend.core.model.data.QRecordWithStatus; +import com.kingsrook.qqq.backend.core.modules.interfaces.InsertInterface; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class MockInsertAction implements InsertInterface +{ + + /******************************************************************************* + ** + *******************************************************************************/ + public InsertResult execute(InsertRequest insertRequest) throws QException + { + try + { + InsertResult rs = new InsertResult(); + + rs.setRecords(insertRequest.getRecords().stream().map(qRecord -> + { + return new QRecordWithStatus(qRecord); + }).toList()); + + return rs; + } + catch(Exception e) + { + throw new QException("Error executing insert: " + e.getMessage(), e); + } + } + +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockModule.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockModule.java new file mode 100644 index 00000000..ea546ca3 --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockModule.java @@ -0,0 +1,33 @@ +package com.kingsrook.qqq.backend.core.modules.mock; + + +import com.kingsrook.qqq.backend.core.modules.interfaces.InsertInterface; +import com.kingsrook.qqq.backend.core.modules.interfaces.QModuleInterface; +import com.kingsrook.qqq.backend.core.modules.interfaces.QueryInterface; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class MockModule implements QModuleInterface +{ + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public QueryInterface getQueryInterface() + { + return new MockQueryAction(); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public InsertInterface getInsertInterface() + { + return (new MockInsertAction()); + } +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockQueryAction.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockQueryAction.java new file mode 100644 index 00000000..a357deef --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockQueryAction.java @@ -0,0 +1,51 @@ +package com.kingsrook.qqq.backend.core.modules.mock; + + +import java.util.ArrayList; +import java.util.List; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.QueryRequest; +import com.kingsrook.qqq.backend.core.model.actions.QueryResult; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData; +import com.kingsrook.qqq.backend.core.modules.interfaces.QueryInterface; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class MockQueryAction implements QueryInterface +{ + + /******************************************************************************* + ** + *******************************************************************************/ + public QueryResult execute(QueryRequest queryRequest) throws QException + { + try + { + QTableMetaData table = queryRequest.getTable(); + + QueryResult rs = new QueryResult(); + List records = new ArrayList<>(); + rs.setRecords(records); + + QRecord record = new QRecord(); + records.add(record); + record.setTableName(table.getName()); + + for(String field : table.getFields().keySet()) + { + record.setValue(field, "1"); + } + + return rs; + } + catch(Exception e) + { + e.printStackTrace(); + throw new QException("Error executing query", e); + } + } + +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/utils/CollectionUtils.java b/src/main/java/com/kingsrook/qqq/backend/core/utils/CollectionUtils.java index a4d41eae..155a1bfe 100755 --- a/src/main/java/com/kingsrook/qqq/backend/core/utils/CollectionUtils.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/utils/CollectionUtils.java @@ -251,7 +251,7 @@ public class CollectionUtils { List> rs = new LinkedList<>(); - if(values.isEmpty()) + if(values == null || values.isEmpty()) { ////////////////////////////////////////////////////////////////// // if there are no input values, return an empty list of lists. // diff --git a/src/main/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtils.java b/src/main/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtils.java new file mode 100644 index 00000000..2100e38d --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtils.java @@ -0,0 +1,34 @@ +package com.kingsrook.qqq.backend.core.utils; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class ExceptionUtils +{ + + /******************************************************************************* + ** + *******************************************************************************/ + public static T findClassInRootChain(Throwable e, Class targetClass) + { + if (e == null) + { + return (null); + } + + if(e.getClass().equals(targetClass)) + { + //noinspection unchecked + return ((T) e); + } + + if(e.getCause() == null) + { + return (null); + } + + return findClassInRootChain(e.getCause(), targetClass); + } + +} diff --git a/src/test/java/com/kingsrook/qqq/backend/core/actions/InsertActionTest.java b/src/test/java/com/kingsrook/qqq/backend/core/actions/InsertActionTest.java new file mode 100644 index 00000000..c3a24c3d --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/actions/InsertActionTest.java @@ -0,0 +1,38 @@ +package com.kingsrook.qqq.backend.core.actions; + + +import java.util.ArrayList; +import java.util.List; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.InsertRequest; +import com.kingsrook.qqq.backend.core.model.actions.InsertResult; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +/******************************************************************************* + ** + *******************************************************************************/ +class InsertActionTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test() throws QException + { + InsertRequest request = new InsertRequest(TestUtils.defineInstance()); + request.setTableName("person"); + List records =new ArrayList<>(); + QRecord record = new QRecord(); + record.setValue("firstName", "James"); + records.add(record); + request.setRecords(records); + InsertResult result = new InsertAction().execute(request); + assertNotNull(result); + } + +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/actions/MetaDataActionTest.java b/src/test/java/com/kingsrook/qqq/backend/core/actions/MetaDataActionTest.java new file mode 100644 index 00000000..9db3254a --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/actions/MetaDataActionTest.java @@ -0,0 +1,32 @@ +package com.kingsrook.qqq.backend.core.actions; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.MetaDataRequest; +import com.kingsrook.qqq.backend.core.model.actions.MetaDataResult; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + + +/******************************************************************************* + ** + *******************************************************************************/ +class MetaDataActionTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test() throws QException + { + MetaDataRequest request = new MetaDataRequest(TestUtils.defineInstance()); + MetaDataResult result = new MetaDataAction().execute(request); + assertNotNull(result); + assertNotNull(result.getTables()); + assertNotNull(result.getTables().get("person")); + assertEquals("person", result.getTables().get("person").getName()); + assertEquals("Person", result.getTables().get("person").getLabel()); + } +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/actions/QueryActionTest.java b/src/test/java/com/kingsrook/qqq/backend/core/actions/QueryActionTest.java new file mode 100644 index 00000000..81558133 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/actions/QueryActionTest.java @@ -0,0 +1,29 @@ +package com.kingsrook.qqq.backend.core.actions; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.QueryRequest; +import com.kingsrook.qqq.backend.core.model.actions.QueryResult; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +/******************************************************************************* + ** + *******************************************************************************/ +class QueryActionTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test() throws QException + { + QueryRequest request = new QueryRequest(TestUtils.defineInstance()); + request.setTableName("person"); + QueryResult result = new QueryAction().execute(request); + assertNotNull(result); + } +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/actions/TableMetaDataActionTest.java b/src/test/java/com/kingsrook/qqq/backend/core/actions/TableMetaDataActionTest.java new file mode 100644 index 00000000..68dd21a4 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/actions/TableMetaDataActionTest.java @@ -0,0 +1,51 @@ +package com.kingsrook.qqq.backend.core.actions; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; +import com.kingsrook.qqq.backend.core.model.actions.TableMetaDataRequest; +import com.kingsrook.qqq.backend.core.model.actions.TableMetaDataResult; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +/******************************************************************************* + ** + *******************************************************************************/ +class TableMetaDataActionTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test() throws QException + { + TableMetaDataRequest request = new TableMetaDataRequest(TestUtils.defineInstance()); + request.setTableName("person"); + TableMetaDataResult result = new TableMetaDataAction().execute(request); + assertNotNull(result); + assertNotNull(result.getTable()); + assertEquals("person", result.getTable().getName()); + assertEquals("Person", result.getTable().getLabel()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test_notFound() + { + assertThrows(QUserFacingException.class, () -> { + TableMetaDataRequest request = new TableMetaDataRequest(TestUtils.defineInstance()); + request.setTableName("willNotBeFound"); + new TableMetaDataAction().execute(request); + }); + } + +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceEnricherTest.java b/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceEnricherTest.java new file mode 100644 index 00000000..cbcaab0a --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceEnricherTest.java @@ -0,0 +1,66 @@ +package com.kingsrook.qqq.backend.core.instances; + + +import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + + +/******************************************************************************* + ** + *******************************************************************************/ +class QInstanceEnricherTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test_nullTableLabelComesFromName() + { + QInstance qInstance = TestUtils.defineInstance(); + QTableMetaData personTable = qInstance.getTable("person"); + personTable.setLabel(null); + assertNull(personTable.getLabel()); + new QInstanceEnricher().enrich(qInstance); + assertEquals("Person", personTable.getLabel()); + } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test_nullNameGivesNullLabel() + { + QInstance qInstance = TestUtils.defineInstance(); + QTableMetaData personTable = qInstance.getTable("person"); + personTable.setLabel(null); + personTable.setName(null); + assertNull(personTable.getLabel()); + assertNull(personTable.getName()); + new QInstanceEnricher().enrich(qInstance); + assertNull(personTable.getLabel()); + assertNull(personTable.getName()); + } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test_nullFieldLabelComesFromName() + { + QInstance qInstance = TestUtils.defineInstance(); + QFieldMetaData idField = qInstance.getTable("person").getField("id"); + idField.setLabel(null); + assertNull(idField.getLabel()); + new QInstanceEnricher().enrich(qInstance); + assertEquals("Id", idField.getLabel()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/modules/QModuleDispatcherTest.java b/src/test/java/com/kingsrook/qqq/backend/core/modules/QModuleDispatcherTest.java new file mode 100644 index 00000000..3f1849ea --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/modules/QModuleDispatcherTest.java @@ -0,0 +1,44 @@ +package com.kingsrook.qqq.backend.core.modules; + + +import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException; +import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; +import com.kingsrook.qqq.backend.core.modules.interfaces.QModuleInterface; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + + +/******************************************************************************* + ** + *******************************************************************************/ +class QModuleDispatcherTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test_getQModule_valid() throws QModuleDispatchException + { + QModuleInterface qModule = new QModuleDispatcher().getQModule(TestUtils.defineBackend()); + assertNotNull(qModule); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test_getQModule_typeNotFound() + { + assertThrows(QModuleDispatchException.class, () -> + { + QBackendMetaData qBackendMetaData = TestUtils.defineBackend(); + qBackendMetaData.setType("aTypeThatWontEverExist"); + new QModuleDispatcher().getQModule(qBackendMetaData); + }); + } + +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/utils/CollectionUtilsTest.java b/src/test/java/com/kingsrook/qqq/backend/core/utils/CollectionUtilsTest.java new file mode 100644 index 00000000..3de81d89 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/utils/CollectionUtilsTest.java @@ -0,0 +1,391 @@ +package com.kingsrook.qqq.backend.core.utils; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/******************************************************************************* + ** + *******************************************************************************/ +class CollectionUtilsTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_nullSafeIsEmpty_Map() + { + assertTrue(CollectionUtils.nullSafeIsEmpty(Collections.emptyMap())); + assertTrue(CollectionUtils.nullSafeIsEmpty(new HashMap<>())); + assertTrue(CollectionUtils.nullSafeIsEmpty((Map) null)); + Map myMap = new HashMap<>(); + assertTrue(CollectionUtils.nullSafeIsEmpty(myMap)); + myMap.put("A", 1); + assertFalse(CollectionUtils.nullSafeIsEmpty(myMap)); + myMap.clear(); + assertTrue(CollectionUtils.nullSafeIsEmpty(myMap)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_nullSafeIsEmpty_Collection() + { + assertTrue(CollectionUtils.nullSafeIsEmpty(Collections.emptyList())); + assertTrue(CollectionUtils.nullSafeIsEmpty(new ArrayList<>())); + assertTrue(CollectionUtils.nullSafeIsEmpty((List) null)); + List myList = new ArrayList<>(); + assertTrue(CollectionUtils.nullSafeIsEmpty(myList)); + myList.add("A"); + assertFalse(CollectionUtils.nullSafeIsEmpty(myList)); + myList.clear(); + assertTrue(CollectionUtils.nullSafeIsEmpty(myList)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_nullSafeHasContents_Map() + { + assertFalse(CollectionUtils.nullSafeHasContents(Collections.emptyMap())); + assertFalse(CollectionUtils.nullSafeHasContents(new HashMap<>())); + assertFalse(CollectionUtils.nullSafeHasContents((Map) null)); + Map myMap = new HashMap<>(); + assertFalse(CollectionUtils.nullSafeHasContents(myMap)); + myMap.put("A", 1); + assertTrue(CollectionUtils.nullSafeHasContents(myMap)); + myMap.clear(); + assertFalse(CollectionUtils.nullSafeHasContents(myMap)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_nullSafeHasContents_Collection() + { + assertFalse(CollectionUtils.nullSafeHasContents(Collections.emptyList())); + assertFalse(CollectionUtils.nullSafeHasContents(new ArrayList<>())); + assertFalse(CollectionUtils.nullSafeHasContents((List) null)); + List myList = new ArrayList<>(); + assertFalse(CollectionUtils.nullSafeHasContents(myList)); + myList.add("A"); + assertTrue(CollectionUtils.nullSafeHasContents(myList)); + myList.clear(); + assertFalse(CollectionUtils.nullSafeHasContents(myList)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_nullSafeSize_Map() + { + assertEquals(0, CollectionUtils.nullSafeSize(Collections.emptyMap())); + assertEquals(0, CollectionUtils.nullSafeSize(new HashMap<>())); + assertEquals(0, CollectionUtils.nullSafeSize((Map) null)); + Map myMap = new HashMap<>(); + assertEquals(0, CollectionUtils.nullSafeSize(myMap)); + myMap.put("A", 1); + assertEquals(1, CollectionUtils.nullSafeSize(myMap)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_nullSafeSize_Collection() + { + assertEquals(0, CollectionUtils.nullSafeSize(Collections.emptyList())); + assertEquals(0, CollectionUtils.nullSafeSize(new ArrayList<>())); + assertEquals(0, CollectionUtils.nullSafeSize((List) null)); + List myList = new ArrayList<>(); + assertEquals(0, CollectionUtils.nullSafeSize(myList)); + myList.add("A"); + assertEquals(1, CollectionUtils.nullSafeSize(myList)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @SuppressWarnings("ConstantConditions") + @Test + void test_addAllToMap() + { + Map to = new HashMap<>(); + Map from = new HashMap<>(); + + assertThrows(NullPointerException.class, () -> CollectionUtils.addAllToMap(null, null)); + assertThrows(NullPointerException.class, () -> CollectionUtils.addAllToMap(to, null)); + + // this case does not currently throw - capture that fact here in case we change it. + CollectionUtils.addAllToMap(null, from); + + CollectionUtils.addAllToMap(to, from); + assertEquals(0, to.size()); + + from.put("A", 1); + CollectionUtils.addAllToMap(to, from); + assertEquals(1, to.size()); + assertEquals(1, to.get("A")); + + from.put("B", 2); + CollectionUtils.addAllToMap(to, from); + assertEquals(2, to.size()); + assertEquals(1, to.get("A")); + assertEquals(2, to.get("B")); + + from.put("B", 3); + CollectionUtils.addAllToMap(to, from); + assertEquals(2, to.size()); + assertEquals(1, to.get("A")); + assertEquals(3, to.get("B")); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_listToMap() + { + assertNull(CollectionUtils.listToMap(null, null)); + + List myList = new ArrayList<>(); + myList.add("Apple"); + myList.add("Banana"); + assertThrows(NullPointerException.class, () -> CollectionUtils.listToMap(myList, null)); + + Map myMap = CollectionUtils.listToMap(myList, first()); + assertEquals(2, myMap.size()); + assertEquals("Apple", myMap.get("A")); + assertEquals("Banana", myMap.get("B")); + + // confirm what a clobbered key does + myList.add("Airplane"); + myMap = CollectionUtils.listToMap(myList, first()); + assertEquals(2, myMap.size()); + assertEquals("Airplane", myMap.get("A")); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_listToMap_valueFunction() + { + assertNull(CollectionUtils.listToMap(null, null, null)); + + List myList = new ArrayList<>(); + myList.add("Apple"); + myList.add("Banana"); + assertThrows(NullPointerException.class, () -> CollectionUtils.listToMap(myList, null, null)); + + Map myMap = CollectionUtils.listToMap(myList, first(), rest()); + assertEquals(2, myMap.size()); + assertEquals("pple", myMap.get("A")); + assertEquals("anana", myMap.get("B")); + + // confirm what a clobbered key does + myList.add("Airplane"); + myMap = CollectionUtils.listToMap(myList, first(), rest()); + assertEquals(2, myMap.size()); + assertEquals("irplane", myMap.get("A")); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_listToListingHash() + { + assertNull(CollectionUtils.listToListingHash(null, null)); + + List myList = new ArrayList<>(); + myList.add("Apple"); + myList.add("Banana"); + assertThrows(NullPointerException.class, () -> CollectionUtils.listToListingHash(myList, null)); + + ListingHash myListingHash = CollectionUtils.listToListingHash(myList, first()); + assertEquals(2, myListingHash.size()); + assertEquals(1, myListingHash.get("A").size()); + assertEquals("Apple", myListingHash.get("A").get(0)); + assertEquals(1, myListingHash.get("B").size()); + assertEquals("Banana", myListingHash.get("B").get(0)); + + myList.add("Airplane"); + myListingHash = CollectionUtils.listToListingHash(myList, first()); + assertEquals(2, myListingHash.size()); + assertEquals(2, myListingHash.get("A").size()); + assertEquals("Apple", myListingHash.get("A").get(0)); + assertEquals("Airplane", myListingHash.get("A").get(1)); + assertEquals(1, myListingHash.get("B").size()); + assertEquals("Banana", myListingHash.get("B").get(0)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_listToListingHash_valueFunction() + { + assertNull(CollectionUtils.listToListingHash(null, null, null)); + + List myList = new ArrayList<>(); + myList.add("Apple"); + myList.add("Banana"); + assertThrows(NullPointerException.class, () -> CollectionUtils.listToListingHash(myList, null, null)); + + ListingHash myListingHash = CollectionUtils.listToListingHash(myList, first(), rest()); + assertEquals(2, myListingHash.size()); + assertEquals(1, myListingHash.get("A").size()); + assertEquals("pple", myListingHash.get("A").get(0)); + assertEquals(1, myListingHash.get("B").size()); + assertEquals("anana", myListingHash.get("B").get(0)); + + myList.add("Airplane"); + myListingHash = CollectionUtils.listToListingHash(myList, first(), rest()); + assertEquals(2, myListingHash.size()); + assertEquals(2, myListingHash.get("A").size()); + assertEquals("pple", myListingHash.get("A").get(0)); + assertEquals("irplane", myListingHash.get("A").get(1)); + assertEquals(1, myListingHash.get("B").size()); + assertEquals("anana", myListingHash.get("B").get(0)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_listTo2LevelMap() + { + assertNull(CollectionUtils.listTo2LevelMap(null, null, null)); + + List myList = new ArrayList<>(); + myList.add("Apple"); + myList.add("Banana"); + myList.add("Airplane"); + assertThrows(NullPointerException.class, () -> CollectionUtils.listTo2LevelMap(myList, null, null)); + assertThrows(NullPointerException.class, () -> CollectionUtils.listTo2LevelMap(myList, first(), null)); + assertThrows(NullPointerException.class, () -> CollectionUtils.listTo2LevelMap(myList, null, second())); + + Map> myMap = CollectionUtils.listTo2LevelMap(myList, first(), second()); + assertEquals(2, myMap.size()); + assertEquals(2, myMap.get("A").size()); + assertEquals("Apple", myMap.get("A").get("p")); + assertEquals("Airplane", myMap.get("A").get("i")); + assertEquals(1, myMap.get("B").size()); + assertEquals("Banana", myMap.get("B").get("a")); + + // demonstrate clobbering behavior + myList.add("Ape"); + myMap = CollectionUtils.listTo2LevelMap(myList, first(), second()); + assertEquals(2, myMap.get("A").size()); + assertEquals("Ape", myMap.get("A").get("p")); + } + + + + /******************************************************************************* + ** helper method to get rest of string (unsafely) + *******************************************************************************/ + private Function rest() + { + return s -> s.substring(1); + } + + + + /******************************************************************************* + ** helper method to get first char of string (unsafely) + *******************************************************************************/ + private Function first() + { + return s -> s.substring(0, 1); + } + + /******************************************************************************* + ** helper method to get second char of string (unsafely) + *******************************************************************************/ + private Function second() + { + return s -> s.substring(1, 2); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_getPages() + { + List> pages = CollectionUtils.getPages(null, 5); + assertEquals(0, pages.size()); + + pages = CollectionUtils.getPages(Collections.emptyList(), 5); + assertEquals(0, pages.size()); + + pages = CollectionUtils.getPages(List.of(1, 2, 3), 5); + assertEquals(1, pages.size()); + assertEquals(3, pages.get(0).size()); + + pages = CollectionUtils.getPages(List.of(1, 2, 3, 4, 5), 5); + assertEquals(1, pages.size()); + assertEquals(5, pages.get(0).size()); + + pages = CollectionUtils.getPages(List.of(1, 2, 3, 4, 5, 6, 7), 5); + assertEquals(2, pages.size()); + assertEquals(5, pages.get(0).size()); + assertEquals(2, pages.get(1).size()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test_getQuestionMarks() + { + assertEquals("", CollectionUtils.getQuestionMarks(null)); + assertEquals("", CollectionUtils.getQuestionMarks(Collections.emptyList())); + assertEquals("?", CollectionUtils.getQuestionMarks(List.of(1))); + assertEquals("?,?,?", CollectionUtils.getQuestionMarks(List.of(1, 2, 3))); + } +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtilsTest.java b/src/test/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtilsTest.java new file mode 100644 index 00000000..8ae2ae74 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtilsTest.java @@ -0,0 +1,29 @@ +package com.kingsrook.qqq.backend.core.utils; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + + +/******************************************************************************* + ** + *******************************************************************************/ +class ExceptionUtilsTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void findClassInRootChain() + { + assertNull(ExceptionUtils.findClassInRootChain(null, QUserFacingException.class)); + QUserFacingException target = new QUserFacingException("target"); + + assertSame(target, ExceptionUtils.findClassInRootChain(target, QUserFacingException.class)); + assertSame(target, ExceptionUtils.findClassInRootChain(new QException("decoy", target), QUserFacingException.class)); + assertNull(ExceptionUtils.findClassInRootChain(new QException("decoy", target), IllegalArgumentException.class)); + } +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/utils/JsonUtilsTest.java b/src/test/java/com/kingsrook/qqq/backend/core/utils/JsonUtilsTest.java index cd66e44b..4f86ff5d 100644 --- a/src/test/java/com/kingsrook/qqq/backend/core/utils/JsonUtilsTest.java +++ b/src/test/java/com/kingsrook/qqq/backend/core/utils/JsonUtilsTest.java @@ -67,6 +67,24 @@ class JsonUtilsTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void test_toJSONObject_malformed() + { + // todo - what do we want to throw here? + assertThrows(JSONException.class, () -> + { + JsonUtils.toJSONObject(""" + { + "Foo": "Bar", + """); + }); + } + + + /******************************************************************************* ** *******************************************************************************/ diff --git a/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java b/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java index ebfb0492..c7c257a3 100644 --- a/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java +++ b/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java @@ -33,12 +33,7 @@ public class TestUtils { return new QBackendMetaData() .withName("default") - .withType("rdbms") - .withValue("vendor", "h2") - .withValue("hostName", "mem") - .withValue("databaseName", "test_database") - .withValue("username", "sa") - .withValue("password", ""); + .withType("mock"); }