Skip to content

Commit

Permalink
Story/3511 setting meta (#908)
Browse files Browse the repository at this point in the history
* add failing test

* save

* save

* fix JavaTypeTranslator

* enable setting meta on basic type on function output

* add test for meta on object

* save

* finish test for setting meta on objects

* implement setting meta on outer input

* clean up

* implement setting meta on outer object

* fix setting meta objects

* add disabled tests for upcomming tasks

* simplify logic

* transform function meta generator tests from xtend to java

* revert checkstyle changes

* fix whitespace

* neaten up logic for meta path setting

* neaten up formatting

* improve variable naming

* implement setting metadata address

* prevent setting of non data type attribues in scoping

* remove noisy errors when non symbols are used on path segments

* address review comments

* prevent using as-key when setting meta

* revert checkstyle change

* fix scoping
  • Loading branch information
davidalk authored Jan 29, 2025
1 parent 4d600bf commit 70e9fb7
Show file tree
Hide file tree
Showing 21 changed files with 534 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@ public List<SemanticToken> markOperation(Operation operation) {
}
}
for (Segment seg : operation.pathAsSegmentList()) {
Attribute segAttr = seg.getAttribute();
RosettaFeature segAttr = seg.getFeature();
if (extensions.isResolved(segAttr)) {
SemanticToken segmentToken = markAttribute(seg, SEGMENT__ATTRIBUTE, segAttr, AttributeType.OUTPUT);
SemanticToken segmentToken = markFeature(seg, SEGMENT__FEATURE, segAttr, AttributeType.OUTPUT);
if (segmentToken != null) {
result.add(segmentToken);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
package com.regnosys.rosetta.generator.java.function;

import com.regnosys.rosetta.generator.java.RosettaJavaPackages;
import com.regnosys.rosetta.tests.RosettaTestInjectorProvider;
import com.regnosys.rosetta.tests.util.CodeGeneratorTestHelper;
import com.rosetta.model.lib.RosettaModelObject;
import com.rosetta.model.lib.meta.FieldWithMeta;
import com.rosetta.model.lib.meta.Reference;
import com.rosetta.model.lib.meta.ReferenceWithMeta;
import com.rosetta.model.metafields.MetaFields;
import org.eclipse.xtext.testing.InjectWith;
import org.eclipse.xtext.testing.extensions.InjectionExtension;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import javax.inject.Inject;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(InjectionExtension.class)
@InjectWith(RosettaTestInjectorProvider.class)
public class FunctionGeneratorMetaTest {

@Inject
FunctionGeneratorHelper functionGeneratorHelper;
@Inject
CodeGeneratorTestHelper generatorTestHelper;

//TODO:canSetMetaLocationOnFunctionBasicOutput


@Test
void canSetMetaAddressOnFunctionBasicOutput() {
var model = """
metaType address string
func MyFunc:
output:
result string (1..1)
[metadata address]
set result: "someValue"
set result -> address: "someLocation"
""";

var code = generatorTestHelper.generateCode(model);

var classes = generatorTestHelper.compileToClasses(code);


var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc");

var result = functionGeneratorHelper.invokeFunc(myFunc, ReferenceWithMeta.class);

var expected = generatorTestHelper.createInstanceUsingBuilder(classes, new RosettaJavaPackages.RootPackage("com.rosetta.model.metafields"), "ReferenceWithMetaString", Map.of(
"value", "someValue",
"reference", Reference.builder().setReference("someLocation")
));

assertEquals(expected, result);
}


@Test
void canSetExternalIdOnFunctionObjectOutput() {
var model = """
metaType id string
func MyFunc:
inputs:
myValue string (1..1)
myReference string (1..1)
output:
result string (1..1)
[metadata id]
set result: myValue
set result -> id: myReference
""";

var code = generatorTestHelper.generateCode(model);
var classes = generatorTestHelper.compileToClasses(code);
var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc");

var result = functionGeneratorHelper.invokeFunc(myFunc, FieldWithMeta.class, "someValue", "someExternalKey");

var expected = generatorTestHelper.createInstanceUsingBuilder(classes, new RosettaJavaPackages.RootPackage("com.rosetta.model.metafields"), "FieldWithMetaString", Map.of(
"value", "someValue",
"meta", MetaFields.builder().setExternalKey("someExternalKey")
));

assertEquals(expected, result);
}


@Disabled //TODO: implement nested setting of meta and then complete this
@Test
void canSetExternalKeyOnFunctionObjectOutput() {
var model = """
metaType key string
metaType reference string
type Foo:
[metadata key]
a string (1..1)
func MyFunc:
inputs:
myReference string (1..1)
output:
result Foo (1..1)
set result -> key: myReference
""";

var code = generatorTestHelper.generateCode(model);
}

@Test
void canSetExternalReferenceOnFunctionObjectOutput() {
var model = """
metaType key string
metaType reference string
type Foo:
[metadata key]
a string (1..1)
func MyFunc:
inputs:
myKey string (1..1)
output:
result Foo (1..1)
[metadata reference]
set result -> reference: myKey
""";

var code = generatorTestHelper.generateCode(model);

var classes = generatorTestHelper.compileToClasses(code);
var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc");

var result = functionGeneratorHelper.invokeFunc(myFunc, ReferenceWithMeta.class, "someExternalReference");

var expected = generatorTestHelper.createInstanceUsingBuilder(classes, new RosettaJavaPackages.RootPackage("com.rosetta.test.model.metafields"), "ReferenceWithMetaFoo", Map.of(
"externalReference", "someExternalReference"
));

assertEquals(expected, result);
}

@Disabled //TODO: implement setting nested meta
@Test
void canSetMetaOnFunctionObjectOutputAndNestedMetaField() {
var model = """
type Foo:
a string (1..1)
b string (1..1)
[metadata scheme]
func MyFunc:
output:
result Foo (1..1)
[metadata scheme]
set result -> scheme: "outerScheme"
set result -> a: "someValueA"
set result -> b: "someValueB"
set result -> b -> scheme: "innerScheme"
""";

var code = generatorTestHelper.generateCode(model);
var classes = generatorTestHelper.compileToClasses(code);
var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc");

var result = functionGeneratorHelper.invokeFunc(myFunc, RosettaModelObject.class);

var expected = generatorTestHelper.createInstanceUsingBuilder(classes, new RosettaJavaPackages.RootPackage("com.rosetta.test.model.metafields"), "FieldWithMetaFoo", Map.of(
"value", generatorTestHelper.createInstanceUsingBuilder(classes, "Foo", Map.of(
"a", "someValueA",
"b", generatorTestHelper.createInstanceUsingBuilder(classes, new RosettaJavaPackages.RootPackage("com.rosetta.model.metafields"), "FieldWithMetaString", Map.of(
"value", "someValueB",
"meta", MetaFields.builder().setScheme("innerScheme")
))
)),
"meta", MetaFields.builder().setScheme("outerScheme")
));

assertEquals(expected, result);
}

@Test
void canSetMetaSchemeOnFunctionObjectOutput() {
var model = """
type Foo:
a string (1..1)
b string (1..1)
func MyFunc:
output:
result Foo (1..1)
[metadata scheme]
set result -> scheme: "outerScheme"
set result -> a: "someValueA"
set result -> b: "someValueB"
""";

var code = generatorTestHelper.generateCode(model);
var classes = generatorTestHelper.compileToClasses(code);
var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc");

var result = functionGeneratorHelper.invokeFunc(myFunc, RosettaModelObject.class);

var expected = generatorTestHelper.createInstanceUsingBuilder(classes, new RosettaJavaPackages.RootPackage("com.rosetta.test.model.metafields"), "FieldWithMetaFoo", Map.of(
"value", generatorTestHelper.createInstanceUsingBuilder(classes, "Foo", Map.of(
"a", "someValueA",
"b", "someValueB"
)),
"meta", MetaFields.builder().setScheme("outerScheme")
));

assertEquals(expected, result);
}

@Test
void canSetMetaSchemeOnFunctionBasicOutput() {
var model = """
func MyFunc:
output:
result string (1..1)
[metadata scheme]
set result: "someValue"
set result -> scheme: "someScheme"
""";

var code = generatorTestHelper.generateCode(model);
var classes = generatorTestHelper.compileToClasses(code);

var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc");

var result = functionGeneratorHelper.invokeFunc(myFunc, FieldWithMeta.class);

var expected = generatorTestHelper.createFieldWithMetaString(classes, "someValue", "someScheme");

assertEquals(expected, result);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package com.regnosys.rosetta.generator.java.function

import com.google.common.collect.ImmutableList
import com.regnosys.rosetta.rosetta.simple.SimplePackage
import com.regnosys.rosetta.generator.java.RosettaJavaPackages.RootPackage
import com.regnosys.rosetta.tests.RosettaTestInjectorProvider
import com.regnosys.rosetta.tests.util.CodeGeneratorTestHelper
import com.regnosys.rosetta.tests.util.ModelHelper
import com.regnosys.rosetta.validation.RosettaIssueCodes
import com.rosetta.model.lib.RosettaModelObject
import com.rosetta.model.lib.meta.FieldWithMeta
import com.rosetta.model.lib.meta.Key
import com.rosetta.model.lib.meta.Reference
import com.rosetta.model.lib.records.Date
import com.rosetta.model.metafields.MetaFields
import java.math.BigDecimal
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId
import java.time.ZonedDateTime
import java.util.Arrays
import java.util.List
import java.util.Map
import javax.inject.Inject
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.extensions.InjectionExtension
import org.eclipse.xtext.testing.validation.ValidationTestHelper
Expand All @@ -26,14 +31,8 @@ import static com.google.common.collect.ImmutableMap.*
import static com.regnosys.rosetta.rosetta.expression.ExpressionPackage.Literals.*
import static org.hamcrest.MatcherAssert.assertThat
import static org.hamcrest.core.IsCollectionContaining.hasItems
import static org.junit.jupiter.api.Assertions.*
import static org.junit.Assert.assertThrows
import javax.inject.Inject
import java.time.LocalDateTime
import com.regnosys.rosetta.generator.java.RosettaJavaPackages.RootPackage
import com.rosetta.model.lib.meta.Key
import com.rosetta.model.lib.meta.Reference
import com.rosetta.model.metafields.MetaFields
import static org.junit.jupiter.api.Assertions.*

@ExtendWith(InjectionExtension)
@InjectWith(RosettaTestInjectorProvider)
Expand All @@ -43,7 +42,7 @@ class FunctionGeneratorTest {
@Inject extension CodeGeneratorTestHelper
@Inject extension ModelHelper
@Inject extension ValidationTestHelper

@Test
def void reportingRuleSupportsRecursion() {
val code = '''
Expand Down Expand Up @@ -3148,6 +3147,7 @@ class FunctionGeneratorTest {
'''
].generateCode

code.compileToClasses
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ class RosettaParsingTest {
@Inject extension ValidationTestHelper
@Inject extension ExpressionParser

@Test
def void testCannotSetEnumAttribute() {
'''
enum FooEnum:
VALUE1
VALUE2
func MyFunc:
output:
result FooEnum (0..1)
set result -> VALUE1: empty
'''.parseRosetta
.assertError(SEGMENT, Diagnostic.LINKING_DIAGNOSTIC, "Couldn't resolve reference to RosettaFeature 'VALUE1'.")
}

@Test
def void testLabelAnnotation() {
'''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class RosettaTypeProviderTest {
RMetaAttribute SCHEME
@BeforeAll
def void setup() {
SCHEME = new RMetaAttribute("scheme", UNCONSTRAINED_STRING, null)
SCHEME = new RMetaAttribute("scheme", UNCONSTRAINED_STRING)
}

private def void assertIsValidWithType(CharSequence expr, RMetaAnnotatedType expectedType, boolean expectedIsMulti, List<RosettaModel> context, String... attributes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2179,6 +2179,30 @@ class RosettaValidatorTest implements RosettaIssueCodes {
"'as-key' can only be used with attributes annotated with [metadata reference] annotation.")
}

@Test
def checkAsKeyUsage_03() {
val model = '''
type WithKey:
[metadata key]
type TypeToUse:
attr WithKey (0..1)
[metadata reference]
attr2 TypeToUse (0..1)
func Bar:
inputs:
in0 WithKey (1..1)
in1 TypeToUse (1..1)
output: result TypeToUse (1..1)
[metadata scheme]
set result -> scheme:
in1 as-key
'''.parseRosetta
model.assertError(AS_KEY_OPERATION, null,
"'as-key' can only be used with attributes annotated with [metadata reference] annotation.")
}

@Test
def checkAsKeyUsage_04() {
val model = '''
Expand Down
Loading

0 comments on commit 70e9fb7

Please sign in to comment.