more entity->QRecord abilities; add TIME & BOOLEAN types

This commit is contained in:
2022-08-01 19:43:59 -05:00
parent 509b6f783b
commit 89a943bc2c
22 changed files with 956 additions and 117 deletions

View File

@ -22,12 +22,15 @@
package com.kingsrook.qqq.backend.core.actions.metadata;
import java.util.Set;
import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput;
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/*******************************************************************************
@ -47,9 +50,18 @@ class MetaDataActionTest
request.setSession(TestUtils.getMockSession());
MetaDataOutput 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());
assertNotNull(result.getProcesses().get("greet"));
assertNotNull(result.getProcesses().get("greetInteractive"));
assertNotNull(result.getProcesses().get("etl.basic"));
assertNotNull(result.getProcesses().get("person.bulkInsert"));
assertNotNull(result.getProcesses().get("person.bulkEdit"));
assertNotNull(result.getProcesses().get("person.bulkDelete"));
}
}

View File

@ -103,7 +103,8 @@ public class RunBackendStepActionTest
case STRING -> "ABC";
case INTEGER -> 42;
case DECIMAL -> new BigDecimal("47");
case DATE, DATE_TIME -> null;
case BOOLEAN -> true;
case DATE, TIME, DATE_TIME -> null;
case TEXT -> """
ABC
XYZ""";

View File

@ -22,8 +22,11 @@
package com.kingsrook.qqq.backend.core.instances;
import java.util.Collections;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.Test;
@ -45,7 +48,7 @@ class QInstanceEnricherTest
@Test
public void test_nullTableLabelComesFromName()
{
QInstance qInstance = TestUtils.defineInstance();
QInstance qInstance = TestUtils.defineInstance();
QTableMetaData personTable = qInstance.getTable("person");
personTable.setLabel(null);
assertNull(personTable.getLabel());
@ -54,6 +57,7 @@ class QInstanceEnricherTest
}
/*******************************************************************************
** Test that a table missing a label and a name doesn't NPE, but just keeps
** the name & label both null.
@ -62,7 +66,7 @@ class QInstanceEnricherTest
@Test
public void test_nullNameGivesNullLabel()
{
QInstance qInstance = TestUtils.defineInstance();
QInstance qInstance = TestUtils.defineInstance();
QTableMetaData personTable = qInstance.getTable("person");
personTable.setLabel(null);
personTable.setName(null);
@ -74,6 +78,7 @@ class QInstanceEnricherTest
}
/*******************************************************************************
** Test that a field missing a label gets the default label applied (name w/ UC-first)
**
@ -81,12 +86,64 @@ class QInstanceEnricherTest
@Test
public void test_nullFieldLabelComesFromName()
{
QInstance qInstance = TestUtils.defineInstance();
QFieldMetaData idField = qInstance.getTable("person").getField("id");
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());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSetInferredFieldBackendNames()
{
QTableMetaData table = new QTableMetaData()
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
.withField(new QFieldMetaData("firstName", QFieldType.INTEGER))
.withField(new QFieldMetaData("nonstandard", QFieldType.INTEGER).withBackendName("whateverImNon_standard"));
QInstanceEnricher.setInferredFieldBackendNames(table);
assertEquals("id", table.getField("id").getBackendName());
assertEquals("first_name", table.getField("firstName").getBackendName());
assertEquals("whateverImNon_standard", table.getField("nonstandard").getBackendName());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSetInferredFieldBackendNamesEdgeCases()
{
///////////////////////////////////////////////////////////////
// make sure none of these cases throw (but all should warn) //
///////////////////////////////////////////////////////////////
QInstanceEnricher.setInferredFieldBackendNames(null);
QInstanceEnricher.setInferredFieldBackendNames(new QTableMetaData());
QInstanceEnricher.setInferredFieldBackendNames(new QTableMetaData().withFields(Collections.emptyMap()));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testInferBackendName()
{
assertEquals("id", QInstanceEnricher.inferBackendName("id"));
assertEquals("word_another_word_more_words", QInstanceEnricher.inferBackendName("wordAnotherWordMoreWords"));
assertEquals("l_ul_ul_ul", QInstanceEnricher.inferBackendName("lUlUlUl"));
assertEquals("starts_upper", QInstanceEnricher.inferBackendName("StartsUpper"));
assertEquals("tla_first", QInstanceEnricher.inferBackendName("TLAFirst"));
assertEquals("word_then_tla_in_middle", QInstanceEnricher.inferBackendName("wordThenTLAInMiddle"));
assertEquals("end_with_tla", QInstanceEnricher.inferBackendName("endWithTLA"));
assertEquals("tla_and_another_tla", QInstanceEnricher.inferBackendName("TLAAndAnotherTLA"));
}
}

View File

@ -162,15 +162,74 @@ class QRecordEntityTest
*******************************************************************************/
@SuppressWarnings("ResultOfMethodCallIgnored")
@Test
void testQTableConstructionFromEntity() throws QException
void testQTableConstructionFromEntityGetterReferences() throws QException
{
QTableMetaData qTableMetaData = new QTableMetaData()
.withField(new QFieldMetaData(Item::getSku))
.withField(new QFieldMetaData(Item::getDescription))
.withField(new QFieldMetaData(Item::getQuantity));
.withField(new QFieldMetaData(Item::getQuantity))
.withField(new QFieldMetaData(Item::getFeatured))
.withField(new QFieldMetaData(Item::getPrice));
assertEquals(QFieldType.STRING, qTableMetaData.getField("sku").getType());
assertEquals(QFieldType.INTEGER, qTableMetaData.getField("quantity").getType());
///////////////////////////////////////////////////////////////
// assert about attributes that came from @QField annotation //
///////////////////////////////////////////////////////////////
assertTrue(qTableMetaData.getField("sku").getIsRequired());
assertFalse(qTableMetaData.getField("quantity").getIsEditable());
assertEquals("is_featured", qTableMetaData.getField("featured").getBackendName());
//////////////////////////////////////////////////////////////////////////
// assert about attributes that weren't specified in @QField annotation //
//////////////////////////////////////////////////////////////////////////
assertTrue(qTableMetaData.getField("sku").getIsEditable());
assertFalse(qTableMetaData.getField("quantity").getIsRequired());
assertNull(qTableMetaData.getField("sku").getBackendName());
/////////////////////////////////////////////////////////////////////
// assert about attributes for fields without a @QField annotation //
/////////////////////////////////////////////////////////////////////
assertTrue(qTableMetaData.getField("price").getIsEditable());
assertFalse(qTableMetaData.getField("price").getIsRequired());
assertNull(qTableMetaData.getField("price").getBackendName());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testQTableConstructionFromEntity() throws QException
{
QTableMetaData qTableMetaData = new QTableMetaData()
.withFieldsFromEntity(Item.class);
assertEquals(QFieldType.STRING, qTableMetaData.getField("sku").getType());
assertEquals(QFieldType.INTEGER, qTableMetaData.getField("quantity").getType());
///////////////////////////////////////////////////////////////
// assert about attributes that came from @QField annotation //
///////////////////////////////////////////////////////////////
assertTrue(qTableMetaData.getField("sku").getIsRequired());
assertFalse(qTableMetaData.getField("quantity").getIsEditable());
assertEquals("is_featured", qTableMetaData.getField("featured").getBackendName());
//////////////////////////////////////////////////////////////////////////
// assert about attributes that weren't specified in @QField annotation //
//////////////////////////////////////////////////////////////////////////
assertTrue(qTableMetaData.getField("sku").getIsEditable());
assertFalse(qTableMetaData.getField("quantity").getIsRequired());
assertNull(qTableMetaData.getField("sku").getBackendName());
/////////////////////////////////////////////////////////////////////
// assert about attributes for fields without a @QField annotation //
/////////////////////////////////////////////////////////////////////
assertTrue(qTableMetaData.getField("price").getIsEditable());
assertFalse(qTableMetaData.getField("price").getIsRequired());
assertNull(qTableMetaData.getField("price").getBackendName());
}

View File

@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.data.testentities;
import java.math.BigDecimal;
import com.kingsrook.qqq.backend.core.model.data.QField;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
@ -31,11 +32,19 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
*******************************************************************************/
public class Item extends QRecordEntity
{
private String sku;
private String description;
private Integer quantity;
@QField(isRequired = true)
private String sku;
@QField()
private String description;
@QField(isEditable = false)
private Integer quantity;
private BigDecimal price;
private Boolean featured;
@QField(backendName = "is_featured")
private Boolean featured;

View File

@ -32,16 +32,13 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
@ -50,10 +47,13 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMet
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.modules.authentication.MockAuthenticationModule;
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.mock.MockBackendModule;
import com.kingsrook.qqq.backend.core.processes.implementations.etl.basic.BasicETLProcess;
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
/*******************************************************************************
@ -62,9 +62,15 @@ import com.kingsrook.qqq.backend.core.processes.implementations.etl.basic.BasicE
*******************************************************************************/
public class TestUtils
{
public static String DEFAULT_BACKEND_NAME = "default";
public static String PROCESS_NAME_GREET_PEOPLE = "greet";
public static String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
public static final String DEFAULT_BACKEND_NAME = "default";
public static final String TABLE_NAME_PERSON = "person";
public static final String PROCESS_NAME_GREET_PEOPLE = "greet";
public static final String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
public static final String PROCESS_NAME_ADD_TO_PEOPLES_AGE = "addToPeoplesAge";
public static final String TABLE_NAME_PERSON_FILE = "personFile";
public static final String TABLE_NAME_ID_AND_NAME_ONLY = "idAndNameOnly";
@ -138,7 +144,7 @@ public class TestUtils
public static QTableMetaData defineTablePerson()
{
return new QTableMetaData()
.withName("person")
.withName(TABLE_NAME_PERSON)
.withLabel("Person")
.withBackendName(DEFAULT_BACKEND_NAME)
.withPrimaryKeyField("id")
@ -160,7 +166,7 @@ public class TestUtils
public static QTableMetaData definePersonFileTable()
{
return (new QTableMetaData()
.withName("personFile")
.withName(TABLE_NAME_PERSON_FILE)
.withLabel("Person File")
.withBackendName(DEFAULT_BACKEND_NAME)
.withPrimaryKeyField("id")
@ -175,7 +181,7 @@ public class TestUtils
public static QTableMetaData defineTableIdAndNameOnly()
{
return new QTableMetaData()
.withName("idAndNameOnly")
.withName(TABLE_NAME_ID_AND_NAME_ONLY)
.withLabel("Id and Name Only")
.withBackendName(DEFAULT_BACKEND_NAME)
.withPrimaryKeyField("id")
@ -192,7 +198,7 @@ public class TestUtils
{
return new QProcessMetaData()
.withName(PROCESS_NAME_GREET_PEOPLE)
.withTableName("person")
.withTableName(TABLE_NAME_PERSON)
.addStep(new QBackendStepMetaData()
.withName("prepare")
.withCode(new QCodeReference()
@ -200,14 +206,14 @@ public class TestUtils
.withCodeType(QCodeType.JAVA)
.withCodeUsage(QCodeUsage.BACKEND_STEP)) // todo - needed, or implied in this context?
.withInputData(new QFunctionInputMetaData()
.withRecordListMetaData(new QRecordListMetaData().withTableName("person"))
.withRecordListMetaData(new QRecordListMetaData().withTableName(TABLE_NAME_PERSON))
.withFieldList(List.of(
new QFieldMetaData("greetingPrefix", QFieldType.STRING),
new QFieldMetaData("greetingSuffix", QFieldType.STRING)
)))
.withOutputMetaData(new QFunctionOutputMetaData()
.withRecordListMetaData(new QRecordListMetaData()
.withTableName("person")
.withTableName(TABLE_NAME_PERSON)
.addField(new QFieldMetaData("fullGreeting", QFieldType.STRING))
)
.withFieldList(List.of(new QFieldMetaData("outputMessage", QFieldType.STRING))))
@ -223,7 +229,7 @@ public class TestUtils
{
return new QProcessMetaData()
.withName(PROCESS_NAME_GREET_PEOPLE_INTERACTIVE)
.withTableName("person")
.withTableName(TABLE_NAME_PERSON)
.addStep(new QFrontendStepMetaData()
.withName("setup")
@ -238,14 +244,14 @@ public class TestUtils
.withCodeType(QCodeType.JAVA)
.withCodeUsage(QCodeUsage.BACKEND_STEP)) // todo - needed, or implied in this context?
.withInputData(new QFunctionInputMetaData()
.withRecordListMetaData(new QRecordListMetaData().withTableName("person"))
.withRecordListMetaData(new QRecordListMetaData().withTableName(TABLE_NAME_PERSON))
.withFieldList(List.of(
new QFieldMetaData("greetingPrefix", QFieldType.STRING),
new QFieldMetaData("greetingSuffix", QFieldType.STRING)
)))
.withOutputMetaData(new QFunctionOutputMetaData()
.withRecordListMetaData(new QRecordListMetaData()
.withTableName("person")
.withTableName(TABLE_NAME_PERSON)
.addField(new QFieldMetaData("fullGreeting", QFieldType.STRING))
)
.withFieldList(List.of(new QFieldMetaData("outputMessage", QFieldType.STRING))))
@ -270,8 +276,8 @@ public class TestUtils
private static QProcessMetaData defineProcessAddToPeoplesAge()
{
return new QProcessMetaData()
.withName("addToPeoplesAge")
.withTableName("person")
.withName(PROCESS_NAME_ADD_TO_PEOPLES_AGE)
.withTableName(TABLE_NAME_PERSON)
.addStep(new QBackendStepMetaData()
.withName("getAgeStatistics")
.withCode(new QCodeReference()
@ -279,10 +285,10 @@ public class TestUtils
.withCodeType(QCodeType.JAVA)
.withCodeUsage(QCodeUsage.BACKEND_STEP))
.withInputData(new QFunctionInputMetaData()
.withRecordListMetaData(new QRecordListMetaData().withTableName("person")))
.withRecordListMetaData(new QRecordListMetaData().withTableName(TABLE_NAME_PERSON)))
.withOutputMetaData(new QFunctionOutputMetaData()
.withRecordListMetaData(new QRecordListMetaData()
.withTableName("person")
.withTableName(TABLE_NAME_PERSON)
.addField(new QFieldMetaData("age", QFieldType.INTEGER)))
.withFieldList(List.of(
new QFieldMetaData("minAge", QFieldType.INTEGER),
@ -297,7 +303,7 @@ public class TestUtils
.withFieldList(List.of(new QFieldMetaData("yearsToAdd", QFieldType.INTEGER))))
.withOutputMetaData(new QFunctionOutputMetaData()
.withRecordListMetaData(new QRecordListMetaData()
.withTableName("person")
.withTableName(TABLE_NAME_PERSON)
.addField(new QFieldMetaData("newAge", QFieldType.INTEGER)))));
}

View File

@ -24,8 +24,16 @@ package com.kingsrook.qqq.backend.core.utils;
import java.math.BigDecimal;
import java.math.MathContext;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.GregorianCalendar;
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
@ -41,6 +49,7 @@ class ValueUtilsTest
@Test
void testGetValueAsString() throws QValueException
{
//noinspection ConstantConditions
assertNull(ValueUtils.getValueAsString(null));
assertEquals("", ValueUtils.getValueAsString(""));
assertEquals(" ", ValueUtils.getValueAsString(" "));
@ -132,7 +141,9 @@ class ValueUtilsTest
assertEquals(new BigDecimal("1"), ValueUtils.getValueAsBigDecimal(1.0F));
assertEquals(new BigDecimal("1"), ValueUtils.getValueAsBigDecimal(1.0D));
assertEquals(new BigDecimal("1000000000000"), ValueUtils.getValueAsBigDecimal(1_000_000_000_000L));
//noinspection ConstantConditions
assertEquals(0, new BigDecimal("1.1").compareTo(ValueUtils.getValueAsBigDecimal(1.1F).round(MathContext.DECIMAL32)));
//noinspection ConstantConditions
assertEquals(0, new BigDecimal("1.1").compareTo(ValueUtils.getValueAsBigDecimal(1.1D).round(MathContext.DECIMAL64)));
assertThrows(QValueException.class, () -> ValueUtils.getValueAsBigDecimal("a"));
@ -140,4 +151,79 @@ class ValueUtilsTest
assertThrows(QValueException.class, () -> ValueUtils.getValueAsBigDecimal(new Object()));
}
/*******************************************************************************
**
*******************************************************************************/
@SuppressWarnings("deprecation")
@Test
void testGetValueAsLocalDate() throws QValueException
{
assertNull(ValueUtils.getValueAsLocalDate(null));
assertNull(ValueUtils.getValueAsLocalDate(""));
assertNull(ValueUtils.getValueAsLocalDate(" "));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDate.of(1980, 5, 31)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.sql.Date(80, 4, 31)));
//noinspection MagicConstant
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, 4, 31)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 12, 0)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 4, 0)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 22, 0)));
//noinspection MagicConstant
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, 4, 31)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, Calendar.MAY, 31)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 12, 0)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 4, 0)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 22, 0)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, Month.MAY, 31, 12, 0)));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate("1980-05-31"));
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate("05/31/1980"));
assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("a"));
assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("a,b"));
assertThat(assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("1980/05/31")).getMessage()).contains("parse");
assertThat(assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate(new Object())).getMessage()).contains("Unsupported class");
}
/*******************************************************************************
**
*******************************************************************************/
@SuppressWarnings("deprecation")
@Test
void testGetValueAsInstant() throws QValueException
{
Instant expected = Instant.parse("1980-05-31T12:30:00Z");
assertNull(ValueUtils.getValueAsInstant(null));
assertNull(ValueUtils.getValueAsInstant(""));
assertNull(ValueUtils.getValueAsInstant(" "));
assertEquals(expected, ValueUtils.getValueAsInstant(expected));
assertEquals(expected, ValueUtils.getValueAsInstant("1980-05-31T12:30:00Z"));
////////////////////////////
// todo - time zone logic //
////////////////////////////
// //noinspection MagicConstant
// assertEquals(expected, ValueUtils.getValueAsInstant(new java.util.Date(80, 4, 31, 7, 30)));
// //noinspection MagicConstant
// assertEquals(expected, ValueUtils.getValueAsInstant(new GregorianCalendar(1980, 4, 31)));
// assertEquals(expected, ValueUtils.getValueAsInstant(new GregorianCalendar(1980, Calendar.MAY, 31)));
// // assertEquals(expected, ValueUtils.getValueAsInstant(InstantTime.of(1980, 5, 31, 12, 0)));
// // assertEquals(expected, ValueUtils.getValueAsInstant(InstantTime.of(1980, 5, 31, 4, 0)));
// // assertEquals(expected, ValueUtils.getValueAsInstant(InstantTime.of(1980, 5, 31, 22, 0)));
// // assertEquals(expected, ValueUtils.getValueAsInstant(InstantTime.of(1980, Month.MAY, 31, 12, 0)));
assertThrows(QValueException.class, () -> ValueUtils.getValueAsInstant(new java.sql.Date(80, 4, 31)));
assertThrows(QValueException.class, () -> ValueUtils.getValueAsInstant("a"));
assertThrows(QValueException.class, () -> ValueUtils.getValueAsInstant("a,b"));
assertThrows(QValueException.class, () -> ValueUtils.getValueAsInstant("1980/05/31"));
assertThat(assertThrows(QValueException.class, () -> ValueUtils.getValueAsInstant(new Object())).getMessage()).contains("Unsupported class");
}
}