> 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);
+ }
+}