diff --git a/pom.xml b/pom.xml index faeabee..c07483c 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ - 5.0.0 + 5.1.0 UTF-8 @@ -60,18 +60,18 @@ 1.6.0 - 3.4.0 + 3.5.2 3.3.1 - 3.1.2 - 3.1.2 - 3.8.0 - 3.2.5 - 0.5.0 + 3.1.3 + 3.1.3 + 3.11.2 + 3.2.7 + 0.7.0 - 2.11.0 - 4.3.0 - 5.11.0 + 2.12.1 + 4.4.0 + 5.11.4 0.8.12 @@ -418,4 +418,4 @@ - \ No newline at end of file + diff --git a/protobuf/pom.xml b/protobuf/pom.xml index fcfbdf4..8c847bb 100644 --- a/protobuf/pom.xml +++ b/protobuf/pom.xml @@ -34,8 +34,8 @@ 1.4.1 - 3.25.4 - 3.25.4 + 3.25.6 + 3.25.6 diff --git a/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/ProtobufBinaryTaskitEngine.java b/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/ProtobufBinaryTaskitEngine.java new file mode 100644 index 0000000..b01811c --- /dev/null +++ b/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/ProtobufBinaryTaskitEngine.java @@ -0,0 +1,209 @@ +package gov.hhs.aspr.ms.taskit.protobuf.engine; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Message; +import com.google.protobuf.ProtocolMessageEnum; + +import gov.hhs.aspr.ms.taskit.core.engine.TaskitEngineData; +import gov.hhs.aspr.ms.taskit.core.engine.TaskitError; +import gov.hhs.aspr.ms.taskit.core.translation.ITranslationSpec; +import gov.hhs.aspr.ms.taskit.core.translation.Translator; +import gov.hhs.aspr.ms.taskit.core.translation.TranslatorContext; +import gov.hhs.aspr.ms.taskit.protobuf.translation.ProtobufTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.ProtobufTranslator; +import gov.hhs.aspr.ms.util.errors.ContractException; + +public class ProtobufBinaryTaskitEngine extends ProtobufTaskitEngine { + + protected ProtobufBinaryTaskitEngine(Map> typeUrlToClassMap, TaskitEngineData taskitEngineData) { + super(typeUrlToClassMap, taskitEngineData, ProtobufTaskitEngineId.BINARY_ENGINE_ID); + } + + /** + * Builder for the ProtobufJsonTaskitEngine. + */ + public final static class Builder implements IProtobufTaskitEngineBuilder { + private Set descriptorSet = new LinkedHashSet<>(); + + // this is used specifically for Any message types to pack and unpack them + private final Map> typeUrlToClassMap = new LinkedHashMap<>(); + + private TaskitEngineData.Builder taskitEngineDataBuilder = TaskitEngineData.builder(); + + private Builder() { + } + + /** + * Returns a new instance of a ProtobufTaskitEngine that has a jsonParser and + * jsonWriter that include all the typeUrls for all added TranslationSpecs and + * their respective Protobuf Message types. + * + * @throws ContractException + *
    + *
  • {@link TaskitError#UNINITIALIZED_TRANSLATORS} + * if translators were added to the engine but their + * initialized flag was still set to false
  • + *
  • {@link TaskitError#DUPLICATE_TRANSLATOR} if a + * duplicate translator is found
  • + *
  • {@link TaskitError#MISSING_TRANSLATOR} if an + * added translator has a unmet dependency
  • + *
  • {@link TaskitError#CIRCULAR_TRANSLATOR_DEPENDENCIES} + * if the added translators have a circular dependency + * graph
  • + *
  • {@link TaskitError#NO_TRANSLATION_SPECS} if no + * translation specs were added to the engine
  • + *
+ */ + public ProtobufBinaryTaskitEngine build() { + this.addTranslator(ProtobufTranslator.getTranslator()); + + ProtobufBinaryTaskitEngine protoBinaryTaskitEngine = new ProtobufBinaryTaskitEngine(this.typeUrlToClassMap, + this.taskitEngineDataBuilder.build()); + + protoBinaryTaskitEngine.init(); + + return protoBinaryTaskitEngine; + } + + /** + * Adds the given {@link ITranslationSpec} to the TaskitEngine. + *

+ * Additionally will populate typeUrls and field descriptors associated with the + * Protobuf types on the given TranslationSpec. + *

+ * + * @throws ContractException + *
    + *
  • {@linkplain TaskitError#NULL_TRANSLATION_SPEC} + * if the given translationSpec is null
  • + *
  • {@linkplain TaskitError#NULL_TRANSLATION_SPEC_CLASS_MAP} + * if the given translationSpec's class map is + * null
  • + *
  • {@linkplain TaskitError#EMPTY_TRANSLATION_SPEC_CLASS_MAP} + * if the given translationSpec's class map is + * empty
  • + *
  • {@linkplain TaskitError#DUPLICATE_TRANSLATION_SPEC} + * if the given translationSpec is already known
  • + *
  • {@link ProtobufTaskitError#INVALID_TRANSLATION_SPEC} + * if the given translation spec is not assignable + * from {@linkplain ProtobufTranslationSpec}
  • + *
  • {@link ProtobufTaskitError#INVALID_TRANSLATION_SPEC_INPUT_CLASS} + * if the given inputClassRef is not assignable from + * {@linkplain Message} nor + * {@linkplain ProtocolMessageEnum}
  • + *
+ */ + @Override + public Builder addTranslationSpec(ITranslationSpec translationSpec) { + this.taskitEngineDataBuilder.addTranslationSpec(translationSpec); + + if (!ProtobufTranslationSpec.class.isAssignableFrom(translationSpec.getClass())) { + throw new ContractException(ProtobufTaskitError.INVALID_TRANSLATION_SPEC); + } + + ProtobufTranslationSpec protobufTranslationSpec = ProtobufTranslationSpec.class.cast(translationSpec); + + populate(protobufTranslationSpec.getInputObjectClass()); + return this; + } + + /** + * Adds a {@link Translator}. + * + * @throws ContractException {@linkplain TaskitError#NULL_TRANSLATOR} if + * translator is null + */ + @Override + public Builder addTranslator(Translator translator) { + this.taskitEngineDataBuilder.addTranslator(translator); + + translator.initialize(new TranslatorContext(this)); + + return this; + } + + /** + * Checks the class to determine if it is a ProtocolMessageEnum or a Message. + *

+ * If it is a Message, gets the Descriptor (which is akin to a class but for a + * Protobuf + * Message) for it to get the full name and add the typeUrl to the internal + * descriptorMap and typeUrlToClassMap. + *

+ *

+ * Package access for testing. + *

+ * + * @param the type of the classRef + * @param classRef the classRef to use + * + * @throws ContractException {@link ProtobufTaskitError#INVALID_TRANSLATION_SPEC_INPUT_CLASS} + * if the given inputClassRef is not assignable from + * {@linkplain Message} nor + * {@linkplain ProtocolMessageEnum} + * + * @throws RuntimeException if there is any issue using reflection to invoke + * either the 'getDefaultInstance' method on a + * {@link Message} type or invoking the 'forNumber(0)' + * method on the {@link ProtocolMessageEnum} type + */ + void populate(Class classRef) { + String typeUrl; + if (ProtocolMessageEnum.class.isAssignableFrom(classRef) && ProtocolMessageEnum.class != classRef) { + typeUrl = ProtobufTaskitEngineHelper.getDefaultEnum(classRef.asSubclass(ProtocolMessageEnum.class)) + .getDescriptorForType().getFullName(); + this.typeUrlToClassMap.putIfAbsent(typeUrl, classRef); + return; + } + + if (Message.class.isAssignableFrom(classRef) && Message.class != classRef) { + Message message = ProtobufTaskitEngineHelper.getDefaultMessage(classRef.asSubclass(Message.class)); + typeUrl = message.getDescriptorForType().getFullName(); + + this.typeUrlToClassMap.putIfAbsent(typeUrl, classRef); + this.descriptorSet.add(message.getDescriptorForType()); + return; + } + + throw new ContractException(ProtobufTaskitError.INVALID_TRANSLATION_SPEC_INPUT_CLASS); + } + + } + + /** + * Returns a new builder for the Protobuf Json Taskit engine. + */ + public static Builder builder() { + return new Builder(); + } + + @Override + protected void writeToFile(File file, Message message) throws IOException { + BufferedOutputStream bOutputStream = new BufferedOutputStream(new FileOutputStream(file)); + + message.writeTo(bOutputStream); + + bOutputStream.flush(); + } + + @Override + protected Message readFile(File file, Message.Builder builder) throws IOException { + BufferedInputStream bInputStream = new BufferedInputStream(new FileInputStream(file)); + + builder.mergeFrom(bInputStream); + + return builder.build(); + } + +} diff --git a/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/ProtobufTaskitError.java b/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/ProtobufTaskitError.java index 47cf755..2c28568 100644 --- a/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/ProtobufTaskitError.java +++ b/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/ProtobufTaskitError.java @@ -11,7 +11,10 @@ public enum ProtobufTaskitError implements ContractError { INVALID_TRANSLATION_SPEC("Added Translation Specs need to be of parent type Protobuf TranslationSpecs"), NULL_FIELD_DESCRIPTOR("The provided field descriptor is null"), UNKNOWN_TYPE_URL( - "The given type url does not have a corresponding classRef. Either the typeUrl was never provided, or the typeUrl is malformed."); + "The given type url does not have a corresponding classRef. Either the typeUrl was never provided, or the typeUrl is malformed."), + MALFORMED_TASKIT_OBJECT("The given taskit object does not have any fields set on it"), + INVALID_RETRIEVAL("Tried to get value on Taskit Object which was not set"), + ; private final String description; diff --git a/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/TaskitObjectHelper.java b/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/TaskitObjectHelper.java new file mode 100644 index 0000000..8c2229d --- /dev/null +++ b/protobuf/src/main/java/gov/hhs/aspr/ms/taskit/protobuf/engine/TaskitObjectHelper.java @@ -0,0 +1,112 @@ +package gov.hhs.aspr.ms.taskit.protobuf.engine; + +import com.google.protobuf.Any; +import com.google.type.Date; + +import gov.hhs.aspr.ms.taskit.protobuf.objects.TaskitObjectInput; +import gov.hhs.aspr.ms.taskit.protobuf.objects.WrapperEnumValue; +import gov.hhs.aspr.ms.util.errors.ContractException; + +public final class TaskitObjectHelper { + + private TaskitObjectHelper() { + } + + public static Object getValue(TaskitObjectInput taskitObjectInput) { + TaskitObjectInput.ValueCase valueCase = taskitObjectInput.getValueCase(); + + switch (valueCase) { + case BVAL: + return taskitObjectInput.getBVal(); + case DATEVAL: + return taskitObjectInput.getDateVal(); + case DVAL: + return taskitObjectInput.getDVal(); + case ENUMVAL: + return taskitObjectInput.getEnumVal(); + case FVAL: + return taskitObjectInput.getFVal(); + case I32VAL: + return taskitObjectInput.getI32Val(); + case I64VAL: + return taskitObjectInput.getI64Val(); + case MVAL: + return taskitObjectInput.getMVal(); + case SVAL: + return taskitObjectInput.getSVal(); + case VALUE_NOT_SET: + default: + throw new ContractException(ProtobufTaskitError.INVALID_RETRIEVAL); + } + } + + public static TaskitObjectInput getTaskitObjectInput(Object value, ProtobufTaskitEngine taskitEngine) { + String valClass = value.getClass().getSimpleName(); + + if (value instanceof Enum) { + valClass = "Enum"; + } + + switch (valClass) { + case "int": + case "Integer": + return getIntegerTaskitInput((Integer) value); + case "long": + case "Long": + return getLongTaskitInput((Long) value); + case "double": + case "Double": + return getDoubleTaskitInput((Double) value); + case "float": + case "Float": + return getFloatTaskitInput((Float) value); + case "boolean": + case "Boolean": + return getBooleanTaskitInput((Boolean) value); + case "String": + return getStringTaskitInput((String) value); + case "LocalDate": + return getDateTaskitInput((Date) taskitEngine.translateObject(value)); + case "Enum": + return getEnumTaskitInput(taskitEngine.translateObjectAsClassSafe(Enum.class.cast(value), Enum.class)); + default: + return getAnyTaskitInput(taskitEngine.getAnyFromObject(value)); + } + } + + static TaskitObjectInput getIntegerTaskitInput(Integer value) { + return TaskitObjectInput.newBuilder().setI32Val(value).build(); + } + + static TaskitObjectInput getAnyTaskitInput(Any value) { + return TaskitObjectInput.newBuilder().setMVal(value).build(); + } + + static TaskitObjectInput getLongTaskitInput(Long value) { + return TaskitObjectInput.newBuilder().setI64Val(value).build(); + } + + static TaskitObjectInput getFloatTaskitInput(Float value) { + return TaskitObjectInput.newBuilder().setFVal(value).build(); + } + + static TaskitObjectInput getDoubleTaskitInput(Double value) { + return TaskitObjectInput.newBuilder().setDVal(value).build(); + } + + static TaskitObjectInput getDateTaskitInput(Date value) { + return TaskitObjectInput.newBuilder().setDateVal(value).build(); + } + + static TaskitObjectInput getStringTaskitInput(String value) { + return TaskitObjectInput.newBuilder().setSVal(value).build(); + } + + static TaskitObjectInput getEnumTaskitInput(WrapperEnumValue value) { + return TaskitObjectInput.newBuilder().setEnumVal(value).build(); + } + + static TaskitObjectInput getBooleanTaskitInput(Boolean value) { + return TaskitObjectInput.newBuilder().setBVal(value).build(); + } +} diff --git a/protobuf/src/main/proto/gov/hhs/aspr/ms/taskit/protobuf/core.proto b/protobuf/src/main/proto/gov/hhs/aspr/ms/taskit/protobuf/core.proto index eb9ac79..7066f63 100644 --- a/protobuf/src/main/proto/gov/hhs/aspr/ms/taskit/protobuf/core.proto +++ b/protobuf/src/main/proto/gov/hhs/aspr/ms/taskit/protobuf/core.proto @@ -4,8 +4,25 @@ package gov.hhs.aspr.ms.taskit.protobuf; option java_multiple_files = true; option java_package = "gov.hhs.aspr.ms.taskit.protobuf.objects"; +import "google/type/date.proto"; +import "google/protobuf/any.proto"; message WrapperEnumValue { string enumTypeUrl = 1; string value = 2; +} + +message TaskitObjectInput { + oneof value { + google.protobuf.Any mVal = 1; + int32 i32Val = 2; + double dVal = 3; + bool bVal = 4; + float fVal = 5; + int64 i64Val = 6; + string sVal = 7; + google.type.Date dateVal = 8; + WrapperEnumValue enumVal = 9; + } + } \ No newline at end of file diff --git a/protobuf/src/test/java/gov/hhs/aspr/ms/taskit/protobuf/engine/AT_ProtobufBinaryTaskitEngine.java b/protobuf/src/test/java/gov/hhs/aspr/ms/taskit/protobuf/engine/AT_ProtobufBinaryTaskitEngine.java new file mode 100644 index 0000000..6247249 --- /dev/null +++ b/protobuf/src/test/java/gov/hhs/aspr/ms/taskit/protobuf/engine/AT_ProtobufBinaryTaskitEngine.java @@ -0,0 +1,216 @@ +package gov.hhs.aspr.ms.taskit.protobuf.engine; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.google.protobuf.Message; +import com.google.protobuf.ProtocolMessageEnum; + +import gov.hhs.aspr.ms.taskit.core.testsupport.objects.TestAppObject; +import gov.hhs.aspr.ms.taskit.core.testsupport.translation.complexobject.TestComplexObjectTranslatorId; +import gov.hhs.aspr.ms.taskit.core.testsupport.translation.object.specs.TestObjectTranslationSpec; +import gov.hhs.aspr.ms.taskit.core.translation.ITranslationSpec; +import gov.hhs.aspr.ms.taskit.core.translation.Translator; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.TestObjectUtil; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.objects.TestComplexInputObject; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.objects.TestInputEnum; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.objects.TestInputObject; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.translation.specs.TestProtobufComplexObjectTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.translation.specs.TestProtobufObjectTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.ProtobufTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.AnyTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.BooleanTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.DateTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.DoubleTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.EnumTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.FloatTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.IntegerTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.LongTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.translation.specs.StringTranslationSpec; +import gov.hhs.aspr.ms.util.annotations.UnitTestForCoverage; +import gov.hhs.aspr.ms.util.annotations.UnitTestMethod; +import gov.hhs.aspr.ms.util.errors.ContractException; +import gov.hhs.aspr.ms.util.resourcehelper.ResourceHelper; + +public class AT_ProtobufBinaryTaskitEngine { + Path basePath = ResourceHelper.getResourceDir(this.getClass()); + Path filePath = ResourceHelper.createDirectory(basePath, "test-output"); + + @Test + @UnitTestForCoverage + public void testReadFile() throws IOException { + String fileName = "readProtoJsonEngine_1-testOutput.bin"; + + ResourceHelper.createFile(filePath, fileName); + + ProtobufBinaryTaskitEngine protobufTaskitEngine = ProtobufBinaryTaskitEngine.builder() + .addTranslationSpec(new TestProtobufObjectTranslationSpec()) + .addTranslationSpec(new TestProtobufComplexObjectTranslationSpec()).build(); + + TestAppObject expectedAppObject = TestObjectUtil.generateTestAppObject(); + TestInputObject expectedObject = TestObjectUtil.getInputFromApp(expectedAppObject); + + protobufTaskitEngine.translateAndWrite(filePath.resolve(fileName), expectedAppObject); + TestInputObject actualObject = protobufTaskitEngine.read(filePath.resolve(fileName), + TestInputObject.class); + assertEquals(expectedObject, actualObject); + } + + @Test + @UnitTestForCoverage + public void testWriteFile() throws IOException { + String fileName = "writeProtoJsonEngine_1-testOutput.bin"; + + ResourceHelper.createFile(filePath, fileName); + + ProtobufBinaryTaskitEngine protobufTaskitEngine = ProtobufBinaryTaskitEngine.builder() + .addTranslationSpec(new TestProtobufObjectTranslationSpec()) + .addTranslationSpec(new TestProtobufComplexObjectTranslationSpec()).build(); + + TestAppObject expectedAppObject = TestObjectUtil.generateTestAppObject(); + TestInputObject testInputObject = TestObjectUtil.getInputFromApp(expectedAppObject); + + protobufTaskitEngine.write(filePath.resolve(fileName), testInputObject); + TestInputObject actualAppObject = protobufTaskitEngine.read(filePath.resolve(fileName), + TestInputObject.class); + assertEquals(testInputObject, actualAppObject); + } + + @Test + @UnitTestMethod(target = ProtobufBinaryTaskitEngine.class, name = "builder", args = {}) + public void testBuilder() { + // Nothing to test + } + + @Test + @UnitTestMethod(target = ProtobufBinaryTaskitEngine.Builder.class, name = "build", args = {}) + public void testBuild() { + + /* + * Test Note: build internally calls TaskitEngineData.build(). As such, the + * build method will also throw the exceptions from that method. Because that is + * already tested in Taskit, the precondition tests will not be tested here + */ + ProtobufBinaryTaskitEngine protobufTaskitEngine = ProtobufBinaryTaskitEngine.builder() + .addTranslationSpec(new TestProtobufComplexObjectTranslationSpec()).build(); + + assertEquals(ProtobufTaskitEngineId.BINARY_ENGINE_ID, protobufTaskitEngine.getTaskitEngineId()); + assertTrue(protobufTaskitEngine.isInitialized()); + + List> list = new ArrayList<>(); + + list.add(new BooleanTranslationSpec()); + list.add(new IntegerTranslationSpec()); + list.add(new LongTranslationSpec()); + list.add(new StringTranslationSpec()); + list.add(new FloatTranslationSpec()); + list.add(new DoubleTranslationSpec()); + list.add(new DateTranslationSpec()); + list.add(new EnumTranslationSpec()); + list.add(new AnyTranslationSpec()); + + for (ProtobufTranslationSpec translationSpec : list) { + translationSpec.init(protobufTaskitEngine); + } + + assertTrue(protobufTaskitEngine.getTranslationSpecs().containsAll(list)); + + // parser and printer do not have equals contracts, so no way to check for + // equality + // the use cases for them are adequately tested in: testReadInput and + // testWriteOutput + } + + @Test + @UnitTestForCoverage + public void testPopulate() { + ProtobufBinaryTaskitEngine.Builder pBuilder = ProtobufBinaryTaskitEngine.builder(); + + // Protobuf Message + pBuilder.populate(TestInputObject.class); + + // Protobuf Enum + pBuilder.populate(TestInputEnum.class); + + // precondition + // if class is neither a Message nor a ProtocolMessageEnum + ContractException contractException = assertThrows(ContractException.class, () -> { + pBuilder.populate(TestAppObject.class); + }); + + assertEquals(ProtobufTaskitError.INVALID_TRANSLATION_SPEC_INPUT_CLASS, contractException.getErrorType()); + + // the class is exactly a Message.class + contractException = assertThrows(ContractException.class, () -> { + pBuilder.populate(Message.class); + }); + + assertEquals(ProtobufTaskitError.INVALID_TRANSLATION_SPEC_INPUT_CLASS, contractException.getErrorType()); + + // the class is exactly a ProtocolMessageEnum.class + contractException = assertThrows(ContractException.class, () -> { + pBuilder.populate(ProtocolMessageEnum.class); + }); + + assertEquals(ProtobufTaskitError.INVALID_TRANSLATION_SPEC_INPUT_CLASS, contractException.getErrorType()); + + } + + @Test + @UnitTestMethod(target = ProtobufBinaryTaskitEngine.Builder.class, name = "addTranslationSpec", args = { + ITranslationSpec.class }) + public void testAddTranslationSpec() { + // base functionality and preconditions tested by core. + // This test will only test the things specifically and uniquely done by the + // ProtobufBinaryTaskitEngine + + ProtobufBinaryTaskitEngine protobufTaskitEngine = ProtobufBinaryTaskitEngine.builder() + .addTranslationSpec(new TestProtobufObjectTranslationSpec()) + .addTranslationSpec(new TestProtobufComplexObjectTranslationSpec()).build(); + + assertDoesNotThrow(() -> { + protobufTaskitEngine.getClassFromTypeUrl(TestInputObject.getDescriptor().getFullName()); + protobufTaskitEngine.getClassFromTypeUrl(TestComplexInputObject.getDescriptor().getFullName()); + }); + + // precondition + // that the inputClass is not a Message nor a + // ProtocolMessageEnum, and is tested in the testPopulate() test + // translation spec is not a protobuf translation spec + ContractException contractException = assertThrows(ContractException.class, () -> { + ProtobufBinaryTaskitEngine.builder() + .addTranslationSpec(new TestObjectTranslationSpec()); + }); + + assertEquals(ProtobufTaskitError.INVALID_TRANSLATION_SPEC, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = ProtobufBinaryTaskitEngine.Builder.class, name = "addTranslator", args = { + Translator.class }) + public void testAddTranslator() { + Translator translator = Translator.builder() + .setTranslatorId(TestComplexObjectTranslatorId.TRANSLATOR_ID) + .setInitializer(translatorContext -> { + translatorContext.getTaskitEngineBuilder(ProtobufBinaryTaskitEngine.Builder.class) + .addTranslationSpec(new TestProtobufComplexObjectTranslationSpec()); + }) + .build(); + + ProtobufBinaryTaskitEngine.builder() + .addTranslator(translator).build(); + + assertTrue(translator.isInitialized()); + + // preconditions tested by core + } +} diff --git a/protobuf/src/test/java/gov/hhs/aspr/ms/taskit/protobuf/engine/AT_TaskitObjectHelper.java b/protobuf/src/test/java/gov/hhs/aspr/ms/taskit/protobuf/engine/AT_TaskitObjectHelper.java new file mode 100644 index 0000000..e76a53f --- /dev/null +++ b/protobuf/src/test/java/gov/hhs/aspr/ms/taskit/protobuf/engine/AT_TaskitObjectHelper.java @@ -0,0 +1,193 @@ +package gov.hhs.aspr.ms.taskit.protobuf.engine; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; + +import com.google.protobuf.Any; +import com.google.type.Date; + +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.TestObjectUtil; +import gov.hhs.aspr.ms.taskit.core.testsupport.objects.TestAppEnum; +import gov.hhs.aspr.ms.taskit.core.testsupport.objects.TestAppObject; +import gov.hhs.aspr.ms.taskit.protobuf.objects.TaskitObjectInput; +import gov.hhs.aspr.ms.taskit.protobuf.objects.WrapperEnumValue; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.translation.specs.TestProtobufComplexObjectTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.translation.specs.TestProtobufEnumTranslationSpec; +import gov.hhs.aspr.ms.taskit.protobuf.testsupport.translation.specs.TestProtobufObjectTranslationSpec; +import gov.hhs.aspr.ms.util.annotations.UnitTestMethod; +import gov.hhs.aspr.ms.util.errors.ContractException; + +public class AT_TaskitObjectHelper { + + @Test + @UnitTestMethod(target = TaskitObjectHelper.class, name = "getValue", args = { + TaskitObjectInput.class }) + public void testHasObjectVal() { + Boolean expectedBoolean = false; + TaskitObjectInput input = TaskitObjectInput.newBuilder().setBVal(expectedBoolean).build(); + + Object actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedBoolean, actualObject); + + Date expectedDate = Date.getDefaultInstance(); + input = TaskitObjectInput.newBuilder().setDateVal(expectedDate).build(); + + actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedDate, actualObject); + + Double expectedDouble = 0.0; + input = TaskitObjectInput.newBuilder().setDVal(expectedDouble).build(); + + actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedDouble, actualObject); + + WrapperEnumValue expectedEnum = WrapperEnumValue.getDefaultInstance(); + input = TaskitObjectInput.newBuilder().setEnumVal(expectedEnum).build(); + + actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedEnum, actualObject); + + Float expectedFloat = 0.0f; + input = TaskitObjectInput.newBuilder().setFVal(expectedFloat).build(); + + actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedFloat, actualObject); + + Integer expectedInt = 0; + input = TaskitObjectInput.newBuilder().setI32Val(expectedInt).build(); + + actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedInt, actualObject); + + Long expectedLong = 0L; + input = TaskitObjectInput.newBuilder().setI64Val(expectedLong).build(); + + actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedLong, actualObject); + + Any expectedAny = Any.pack(WrapperEnumValue.getDefaultInstance()); + input = TaskitObjectInput.newBuilder().setMVal(expectedAny).build(); + + actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedAny, actualObject); + + String expectedString = ""; + input = TaskitObjectInput.newBuilder().setSVal(expectedString).build(); + + actualObject = TaskitObjectHelper.getValue(input); + + assertEquals(expectedString, actualObject); + + // preconditions: + // value was not set + ContractException contractException = assertThrows(ContractException.class, () -> { + TaskitObjectHelper.getValue(TaskitObjectInput.newBuilder().build()); + }); + + assertEquals(ProtobufTaskitError.INVALID_RETRIEVAL, contractException.getErrorType()); + } + + @Test + @UnitTestMethod(target = TaskitObjectHelper.class, name = "getTaskitObjectInput", args = { Object.class, + ProtobufTaskitEngine.class }) + public void testGetTaskitObjectInput() { + + ProtobufTaskitEngine taskitEngine = ProtobufJsonTaskitEngine.builder() + .addTranslationSpec(new TestProtobufComplexObjectTranslationSpec()) + .addTranslationSpec(new TestProtobufEnumTranslationSpec()) + .addTranslationSpec(new TestProtobufObjectTranslationSpec()) + .build(); + + Boolean expectedBoolean = false; + TaskitObjectInput expectedInput = TaskitObjectInput.newBuilder().setBVal(expectedBoolean).build(); + TaskitObjectInput actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedBoolean, taskitEngine); + + assertEquals(expectedInput, actualInput); + + boolean expectedBoolean2 = false; + expectedInput = TaskitObjectInput.newBuilder().setBVal(expectedBoolean2).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedBoolean2, taskitEngine); + + assertEquals(expectedInput, actualInput); + + LocalDate date = LocalDate.now(); + Date expectedDate = taskitEngine.translateObject(date); + expectedInput = TaskitObjectInput.newBuilder().setDateVal(expectedDate).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(date, taskitEngine); + + assertEquals(expectedInput, actualInput); + + Double expectedDouble = 0.0; + expectedInput = TaskitObjectInput.newBuilder().setDVal(expectedDouble).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedDouble, taskitEngine); + + assertEquals(expectedInput, actualInput); + + WrapperEnumValue expectedEnum = taskitEngine.translateObjectAsClassSafe(TestAppEnum.TEST1, Enum.class); + expectedInput = TaskitObjectInput.newBuilder().setEnumVal(expectedEnum).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(TestAppEnum.TEST1, taskitEngine); + + assertEquals(expectedInput, actualInput); + + Float expectedFloat = 0.0f; + expectedInput = TaskitObjectInput.newBuilder().setFVal(expectedFloat).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedFloat, taskitEngine); + + assertEquals(expectedInput, actualInput); + + float expectedFloat2 = 0.0f; + expectedInput = TaskitObjectInput.newBuilder().setFVal(expectedFloat2).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedFloat2, taskitEngine); + + assertEquals(expectedInput, actualInput); + + Integer expectedInt = 0; + expectedInput = TaskitObjectInput.newBuilder().setI32Val(expectedInt).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedInt, taskitEngine); + + assertEquals(expectedInput, actualInput); + + int expectedInt2 = 0; + expectedInput = TaskitObjectInput.newBuilder().setI32Val(expectedInt2).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedInt2, taskitEngine); + + assertEquals(expectedInput, actualInput); + + Long expectedLong = 0L; + expectedInput = TaskitObjectInput.newBuilder().setI64Val(expectedLong).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedLong, taskitEngine); + + assertEquals(expectedInput, actualInput); + + long expectedLong2 = 0L; + expectedInput = TaskitObjectInput.newBuilder().setI64Val(expectedLong2).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedLong2, taskitEngine); + + assertEquals(expectedInput, actualInput); + + TestAppObject obj = TestObjectUtil.generateTestAppObject(); + Any expectedAny = taskitEngine.getAnyFromObject(obj); + expectedInput = TaskitObjectInput.newBuilder().setMVal(expectedAny).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(obj, taskitEngine); + + assertEquals(expectedInput, actualInput); + + String expectedString = ""; + expectedInput = TaskitObjectInput.newBuilder().setSVal(expectedString).build(); + actualInput = TaskitObjectHelper.getTaskitObjectInput(expectedString, taskitEngine); + + assertEquals(expectedInput, actualInput); + } +}