Adding comments and more tests

This commit is contained in:
Darin Kelkhoff
2021-12-01 22:57:45 -06:00
parent c0ad05d119
commit 90cd12e09f
3 changed files with 181 additions and 22 deletions

View File

@ -5,7 +5,6 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -41,8 +40,6 @@ 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.JsonUtils;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.OptionSpec;
@ -52,14 +49,15 @@ import picocli.CommandLine.UnmatchedArgumentException;
/*******************************************************************************
** QQQ PicoCLI implementation. Given a QInstance, produces an entire CLI
** for working with all tables in that instance.
**
** Note: Please do not use System.out or .err here -- rather, use the CommandLine
** object's out & err members - so the unit test can see the output!
*
**
*******************************************************************************/
public class QPicoCliImplementation
{
private static final Logger LOG = LogManager.getLogger(QPicoCliImplementation.class);
public static final int DEFAULT_LIMIT = 20;
private static QInstance qInstance;
@ -274,7 +272,6 @@ public class QPicoCliImplementation
{
CommandSpec deleteCommand = CommandSpec.create();
QFieldMetaData primaryKeyField = table.getField(table.getPrimaryKeyField());
deleteCommand.addOption(OptionSpec.builder("--primaryKey")
.type(String.class) // todo - mmm, better as picocli's "compound" thing, w/ the actual pkey's type?
.build());
@ -287,19 +284,19 @@ public class QPicoCliImplementation
/*******************************************************************************
**
*******************************************************************************/
@SuppressWarnings("checkstyle:Indentation")
private Class<?> getClassForField(QFieldMetaData field)
{
// @formatter:off // IJ can't do new-style switch correctly yet...
return switch(field.getType())
{
case STRING, TEXT, HTML, PASSWORD -> String.class;
case INTEGER -> Integer.class;
case DECIMAL -> BigDecimal.class;
case DATE -> LocalDate.class;
// case TIME -> LocalTime.class;
case DATE_TIME -> LocalDateTime.class;
default -> throw new IllegalStateException("Unsupported field type: " + field.getType());
};
{
case STRING, TEXT, HTML, PASSWORD -> String.class;
case INTEGER -> Integer.class;
case DECIMAL -> BigDecimal.class;
case DATE -> LocalDate.class;
// case TIME -> LocalTime.class;
case DATE_TIME -> LocalDateTime.class;
};
// @formatter:on
}
@ -436,7 +433,7 @@ public class QPicoCliImplementation
/////////////////////////////////////////////
// get the records that the user specified //
/////////////////////////////////////////////
List<QRecord> recordList = null;
List<QRecord> recordList;
if(subParseResult.hasMatchedOption("--jsonBody"))
{
String json = subParseResult.matchedOptionValue("--jsonBody", "");
@ -502,6 +499,7 @@ public class QPicoCliImplementation
}
/*******************************************************************************
**
*******************************************************************************/
@ -509,13 +507,10 @@ public class QPicoCliImplementation
{
DeleteRequest deleteRequest = new DeleteRequest(qInstance);
deleteRequest.setTableName(tableName);
QTableMetaData table = qInstance.getTable(tableName);
/////////////////////////////////////////////
// get the pKeys that the user specified //
/////////////////////////////////////////////
List<Serializable> primaryKeyList = null;
String primaryKeyOption = subParseResult.matchedOptionValue("--primaryKey", "");
String[] primaryKeyValues = primaryKeyOption.split(",");
deleteRequest.setPrimaryKeys(Arrays.asList(primaryKeyValues));

View File

@ -2,12 +2,17 @@ package com.kingsrook.qqq.frontend.picocli;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.UUID;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -17,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/*******************************************************************************
** Unit test for the QPicoCliImplementation.
**
*******************************************************************************/
class QPicoCliImplementationTest
@ -27,6 +33,7 @@ class QPicoCliImplementationTest
/*******************************************************************************
** Fully rebuild the test-database before each test runs, for completely known state.
**
*******************************************************************************/
@BeforeEach
@ -38,6 +45,7 @@ class QPicoCliImplementationTest
/*******************************************************************************
** test that w/ no arguments you just get usage.
**
*******************************************************************************/
@Test
@ -50,6 +58,7 @@ class QPicoCliImplementationTest
/*******************************************************************************
** test that --help gives you usage.
**
*******************************************************************************/
@Test
@ -63,6 +72,7 @@ class QPicoCliImplementationTest
/*******************************************************************************
** test the --verion argument
**
*******************************************************************************/
@Test
@ -75,6 +85,7 @@ class QPicoCliImplementationTest
/*******************************************************************************
** Test that an unrecognized opttion gives an error
**
*******************************************************************************/
@Test
@ -89,6 +100,7 @@ class QPicoCliImplementationTest
/*******************************************************************************
** test the top-level --meta-data option
**
*******************************************************************************/
@Test
@ -108,6 +120,7 @@ class QPicoCliImplementationTest
/*******************************************************************************
** test giving a table-name, gives usage for that table
**
*******************************************************************************/
@Test
@ -121,6 +134,22 @@ class QPicoCliImplementationTest
/*******************************************************************************
** test unknown command under table, prints error and usage.
**
*******************************************************************************/
@Test
public void test_tableUnknownCommand()
{
String badCommand = "qwuijibo";
TestOutput testOutput = testCli("person", badCommand);
assertTrue(testOutput.getError().contains("Unmatched argument at index 1: '" + badCommand + "'"));
assertTrue(testOutput.getError().contains("Usage: " + CLI_NAME + " person [COMMAND]"));
}
/*******************************************************************************
** test requesting table meta-data
**
*******************************************************************************/
@Test
@ -144,6 +173,7 @@ class QPicoCliImplementationTest
/*******************************************************************************
** test running a query on a table
**
*******************************************************************************/
@Test
@ -161,6 +191,134 @@ class QPicoCliImplementationTest
/*******************************************************************************
** test running an insert w/o specifying any fields, prints usage
**
*******************************************************************************/
@Test
public void test_tableInsertNoFieldsPrintsUsage()
{
TestOutput testOutput = testCli("person", "insert");
assertTrue(testOutput.getOutput().contains("Usage: " + CLI_NAME + " person insert"));
}
/*******************************************************************************
** test running an insert w/ fields as arguments
**
*******************************************************************************/
@Test
public void test_tableInsertFieldArguments()
{
TestOutput testOutput = testCli("person", "insert",
"--field-firstName=Lucy",
"--field-lastName=Lu");
JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(insertResult);
assertEquals(1, insertResult.getJSONArray("records").length());
assertEquals(6, insertResult.getJSONArray("records").getJSONObject(0).getInt("primaryKey"));
}
/*******************************************************************************
** test running an insert w/ a mapping and json as an argument
**
*******************************************************************************/
@Test
public void test_tableInsertJsonObjectArgumentWithMapping()
{
String mapping = """
--mapping={"firstName":"first","lastName":"ln"}
""";
String jsonBody = """
--jsonBody={"first":"Chester","ln":"Cheese"}
""";
TestOutput testOutput = testCli("person", "insert", mapping, jsonBody);
JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(insertResult);
assertEquals(1, insertResult.getJSONArray("records").length());
assertEquals(6, insertResult.getJSONArray("records").getJSONObject(0).getInt("primaryKey"));
assertEquals("Chester", insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getString("firstName"));
assertEquals("Cheese", insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getString("lastName"));
}
/*******************************************************************************
** test running an insert w/ a mapping and json as a multi-record file
**
*******************************************************************************/
@Test
public void test_tableInsertJsonArrayFileWithMapping() throws IOException
{
String mapping = """
--mapping={"firstName":"first","lastName":"ln"}
""";
String jsonContents = """
[{"first":"Charlie","ln":"Bear"},{"first":"Coco","ln":"Bean"}]
""";
File file = new File("/tmp/" + UUID.randomUUID() + ".json");
file.deleteOnExit();
FileUtils.writeStringToFile(file, jsonContents);
TestOutput testOutput = testCli("person", "insert", mapping, "--jsonFile=" + file.getAbsolutePath());
JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(insertResult);
JSONArray records = insertResult.getJSONArray("records");
assertEquals(2, records.length());
assertEquals(6, records.getJSONObject(0).getInt("primaryKey"));
assertEquals(7, records.getJSONObject(1).getInt("primaryKey"));
assertEquals("Charlie", records.getJSONObject(0).getJSONObject("values").getString("firstName"));
assertEquals("Bear", records.getJSONObject(0).getJSONObject("values").getString("lastName"));
assertEquals("Coco", records.getJSONObject(1).getJSONObject("values").getString("firstName"));
assertEquals("Bean", records.getJSONObject(1).getJSONObject("values").getString("lastName"));
}
/*******************************************************************************
** test running an insert w/ an index-based mapping and csv file
**
*******************************************************************************/
@Test
public void test_tableInsertCsvFileWithIndexMapping() throws IOException
{
String mapping = """
--mapping={"firstName":1,"lastName":3}
""";
String csvContents = """
"Louis","P","Willikers",1024,
"Nestle","G","Crunch",1701,
""";
File file = new File("/tmp/" + UUID.randomUUID() + ".csv");
file.deleteOnExit();
FileUtils.writeStringToFile(file, csvContents);
TestOutput testOutput = testCli("person", "insert", mapping, "--csvFile=" + file.getAbsolutePath());
JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(insertResult);
JSONArray records = insertResult.getJSONArray("records");
assertEquals(2, records.length());
assertEquals(6, records.getJSONObject(0).getInt("primaryKey"));
assertEquals(7, records.getJSONObject(1).getInt("primaryKey"));
assertEquals("Louis", records.getJSONObject(0).getJSONObject("values").getString("firstName"));
assertEquals("Willikers", records.getJSONObject(0).getJSONObject("values").getString("lastName"));
assertEquals("Nestle", records.getJSONObject(1).getJSONObject("values").getString("firstName"));
assertEquals("Crunch", records.getJSONObject(1).getJSONObject("values").getString("lastName"));
}
/*******************************************************************************
** test running a delete against a table
**
*******************************************************************************/
@Test
@ -330,4 +488,4 @@ class QPicoCliImplementationTest
this.errorLines = errorLines;
}
}
}
}

View File

@ -17,12 +17,14 @@ import static junit.framework.Assert.assertNotNull;
/*******************************************************************************
** Utility methods for unit tests.
**
*******************************************************************************/
public class TestUtils
{
/*******************************************************************************
** Prime a test database (e.g., h2, in-memory)
**
*******************************************************************************/
@SuppressWarnings("unchecked")
@ -43,6 +45,7 @@ public class TestUtils
/*******************************************************************************
** Run an SQL Query in the test database
**
*******************************************************************************/
public static void runTestSql(String sql, QueryManager.ResultSetProcessor resultSetProcessor) throws Exception
@ -55,6 +58,7 @@ public class TestUtils
/*******************************************************************************
** Define the q-instance for testing (h2 rdbms and 'person' table)
**
*******************************************************************************/
public static QInstance defineInstance()
@ -68,6 +72,7 @@ public class TestUtils
/*******************************************************************************
** Define the h2 rdbms backend
**
*******************************************************************************/
public static QBackendMetaData defineBackend()
@ -85,6 +90,7 @@ public class TestUtils
/*******************************************************************************
** Define the person table
**
*******************************************************************************/
public static QTableMetaData defineTablePerson()