Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* added unit test

* Fixes finos#785

* Fixed test

* Cleaned
  • Loading branch information
SimonCockx authored Sep 4, 2024
1 parent ef78afb commit 807477c
Show file tree
Hide file tree
Showing 15 changed files with 268 additions and 71 deletions.
7 changes: 7 additions & 0 deletions rosetta-ide/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@
<include>**/*</include>
</includes>
</fileset>
<!-- xtend -->
<fileset>
<directory>${basedir}/xtend-gen</directory>
<includes>
<include>**/*</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
package com.regnosys.rosetta.ide.server;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.regnosys.rosetta.cache.IRequestScopedCache;

import org.eclipse.xtext.ide.server.concurrent.AbstractRequest;
import org.eclipse.xtext.ide.server.concurrent.RequestManager;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.service.OperationCanceledManager;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.xbase.lib.Functions.Function0;
Expand Down Expand Up @@ -47,6 +50,7 @@ public class RosettaRequestManager extends RequestManager {
.setDaemon(true)
.setNameFormat("rosetta-language-server-request-timeout-%d")
.build());
private final IRequestScopedCache requestCache;

/*
* TODO: contribute to Xtext
Expand All @@ -57,7 +61,7 @@ public class RosettaRequestManager extends RequestManager {
protected List<AbstractRequest<?>> removableRequestList = new CopyOnWriteArrayList<>();

@Inject
public RosettaRequestManager(ExecutorService parallel, OperationCanceledManager operationCanceledManager) {
public RosettaRequestManager(ExecutorService parallel, OperationCanceledManager operationCanceledManager, IResourceServiceProvider.Registry serviceProviderRegistry) {
super(parallel, operationCanceledManager);

String rawTimeout = System.getenv(TIMEOUT_ENV_NAME);
Expand All @@ -66,6 +70,13 @@ public RosettaRequestManager(ExecutorService parallel, OperationCanceledManager
} else {
this.timeout = null;
}

Object serviceProvider = serviceProviderRegistry.getExtensionToFactoryMap().get("rosetta");
if (serviceProvider instanceof IResourceServiceProvider) {
this.requestCache = ((IResourceServiceProvider) serviceProvider).get(IRequestScopedCache.class);
} else {
this.requestCache = null;
}
}

@Override
Expand All @@ -90,7 +101,11 @@ protected CompletableFuture<Void> cancel() {
request.cancel();
cfs[i] = request.get();
}
return CompletableFuture.allOf(cfs);
CompletableFuture<Void> cancelAll = CompletableFuture.allOf(cfs);
if (requestCache != null) {
cancelAll = cancelAll.thenRun(() -> requestCache.clear());
}
return cancelAll;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.regnosys.rosetta.ide.issues

import com.regnosys.rosetta.ide.tests.AbstractRosettaLanguageServerValidationTest
import org.junit.jupiter.api.Test


// Issue https://github.com/finos/rune-dsl/issues/785
class Issue785 extends AbstractRosettaLanguageServerValidationTest {
@Test
def void testIssue785() {
val reportURI = createModel("foo-report.rosetta", '''
namespace foo
import bar.*
body Authority Body
corpus Regulations Corpus
report Body Corpus in T+2
from Event
when Eligible
with type Report
eligibility rule Eligible from Event:
item
reporting rule Thing from Event:
""
''')
createModel("foo-type.rosetta", '''
namespace foo
type Report:
thing string (1..1)
[ruleReference Thing]
''')
val barURI = createModel("bar-type.rosetta", '''
namespace bar
type Event:
''')

// Initial: there should be no issues.
assertNoIssues

// Introduce reference errors in `foo-report.rosetta` by changing the name of `bar.Event` to `bar.Even`.
makeChange(barURI, 2, 5, "Event", "Even")

val issues = diagnostics.get(reportURI)
assertIssues(
'''
Error [[9, 9] .. [9, 14]]: Couldn't resolve reference to RosettaType 'Event'.
Error [[13, 31] .. [13, 36]]: Couldn't resolve reference to RosettaType 'Event'.
Error [[16, 26] .. [16, 31]]: Couldn't resolve reference to RosettaType 'Event'.
Warning [[2, 7] .. [2, 12]]: Unused import bar.*
''',
issues
)
// Change back
makeChange(barURI, 2, 5, "Even", "Event")
// All issues should disappear.
assertNoIssues
}
}
Original file line number Diff line number Diff line change
@@ -1,47 +1,10 @@
package com.regnosys.rosetta.ide.server

import org.junit.jupiter.api.Test
import com.regnosys.rosetta.ide.tests.AbstractRosettaLanguageServerTest
import org.eclipse.xtext.testing.TextDocumentConfiguration
import org.eclipse.lsp4j.DidChangeTextDocumentParams
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier
import org.eclipse.lsp4j.TextDocumentContentChangeEvent
import org.eclipse.lsp4j.Range
import org.eclipse.lsp4j.Position
import java.util.Map
import org.junit.jupiter.api.BeforeEach
import static org.junit.jupiter.api.Assertions.*
import com.regnosys.rosetta.ide.tests.AbstractRosettaLanguageServerValidationTest

class ChangeDetectionTest extends AbstractRosettaLanguageServerTest {
Map<String, Integer> versionMap

@BeforeEach
def void beforeEach() {
versionMap = newHashMap

initializeContext(new TextDocumentConfiguration)
}

private def String createModel(String fileName, String model) {
val uri = fileName.writeFile(model)
open(uri, model)
versionMap.put(uri, 1)
return uri
}
private def void makeChange(String uri, int line, int character, String oldText, String newText) {
val newVersion = versionMap.get(uri) + 1
languageServer.didChange(new DidChangeTextDocumentParams(
new VersionedTextDocumentIdentifier(uri, newVersion),
#[
new TextDocumentContentChangeEvent(
new Range(new Position(line, character), new Position(line, character + oldText.length)),
newText
)
]
));
versionMap.put(uri, newVersion)
}

class ChangeDetectionTest extends AbstractRosettaLanguageServerValidationTest {
@Test
def void testChangeInAttributeTypeIsPropagated() {
val typesURI = createModel("types.rosetta", '''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import com.google.inject.Module
import org.eclipse.lsp4j.DiagnosticSeverity
import com.regnosys.rosetta.RosettaStandaloneSetup
import java.util.HashMap
import org.eclipse.emf.ecore.EPackage
import org.eclipse.emf.ecore.EValidator
import com.regnosys.rosetta.rosetta.RosettaPackage
import com.regnosys.rosetta.rosetta.simple.SimplePackage
import com.regnosys.rosetta.rosetta.expression.ExpressionPackage

/**
* TODO: contribute to Xtext.
Expand All @@ -38,6 +43,11 @@ abstract class AbstractRosettaLanguageServerTest extends AbstractLanguageServerT
}

protected override Module getServerModule() {
EPackage.Registry.INSTANCE.remove(RosettaPackage.eNS_URI);
EPackage.Registry.INSTANCE.remove(SimplePackage.eNS_URI);
EPackage.Registry.INSTANCE.remove(ExpressionPackage.eNS_URI);
EValidator.Registry.INSTANCE.clear

RosettaStandaloneSetup.doSetup
return RosettaServerModule.create
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.regnosys.rosetta.ide.tests

import java.util.Map
import org.junit.jupiter.api.BeforeEach
import org.eclipse.xtext.testing.TextDocumentConfiguration
import org.eclipse.lsp4j.DidChangeTextDocumentParams
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier
import org.eclipse.lsp4j.TextDocumentContentChangeEvent
import org.eclipse.lsp4j.Range
import org.eclipse.lsp4j.Position
import java.util.List
import org.eclipse.lsp4j.Diagnostic

abstract class AbstractRosettaLanguageServerValidationTest extends AbstractRosettaLanguageServerTest {
Map<String, Integer> versionMap

@BeforeEach
def void beforeEach() {
versionMap = newHashMap

initializeContext(new TextDocumentConfiguration)
}

protected def String createModel(String fileName, String model) {
val uri = fileName.writeFile(model)
open(uri, model)
versionMap.put(uri, 1)
return uri
}
protected def void makeChange(String uri, int line, int character, String oldText, String newText) {
val newVersion = versionMap.get(uri) + 1
languageServer.didChange(new DidChangeTextDocumentParams(
new VersionedTextDocumentIdentifier(uri, newVersion),
#[
new TextDocumentContentChangeEvent(
new Range(new Position(line, character), new Position(line, character + oldText.length)),
newText
)
]
));
versionMap.put(uri, newVersion)
}

protected def void assertIssues(String expected, List<Diagnostic> actual) {
assertEquals(
expected,
actual.toExpectation
)
}

protected def dispatch String toExpectation(Diagnostic it) {
'''«severity» «range.toExpectation»: «message»'''
}
}
6 changes: 6 additions & 0 deletions rosetta-lang/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@
<include>**/*</include>
</includes>
</fileset>
<fileset>
<directory>${basedir}/../rosetta-lang/xtend-gen</directory>
<includes>
<include>**/*</include>
</includes>
</fileset>
<!-- rosetta-ide -->
<fileset>
<directory>${basedir}/../rosetta-ide/src-gen/</directory>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import org.eclipse.xtext.validation.IResourceValidator
import com.regnosys.rosetta.validation.CachingResourceValidator
import com.regnosys.rosetta.config.RosettaConfiguration
import com.regnosys.rosetta.config.file.FileBasedRosettaConfigurationProvider
import com.regnosys.rosetta.cache.IRequestScopedCache
import com.regnosys.rosetta.cache.RequestScopedCache

/* Use this class to register components to be used at runtime / without the Equinox extension registry.*/
class RosettaRuntimeModule extends AbstractRosettaRuntimeModule {
Expand Down Expand Up @@ -142,4 +144,8 @@ class RosettaRuntimeModule extends AbstractRosettaRuntimeModule {
def Class<? extends Provider<? extends RosettaConfiguration>> provideRosettaConfiguration() {
FileBasedRosettaConfigurationProvider
}

def Class<? extends IRequestScopedCache> bindIRequestScopedCache() {
RequestScopedCache
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.regnosys.rosetta.cache;

import javax.inject.Provider;

public interface IRequestScopedCache {
<T> T get(Object key, Provider<T> provider);

void clear();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.regnosys.rosetta.cache;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;

/**
* A cache that will clear every time a write request is made. For all subsequent read requests, the cache is reused.
*/
@Singleton
public class RequestScopedCache implements IRequestScopedCache {
// A special object representing a cached null value.
private final Object NULL = new Object();

private final Map<Object, Object> values;

@Inject
public RequestScopedCache() {
this(500);
}
public RequestScopedCache(int initialCapacity) {
this.values = new ConcurrentHashMap<>(initialCapacity);
}

@SuppressWarnings("unchecked")
public <T> T get(Object key, Provider<T> provider) {
Object v = values.get(key);
if (v == NULL) {
return null;
}
if (v != null) {
return (T)v;
}

T computed = provider.get();
if (computed == null) {
values.put(key, NULL);
} else {
values.put(key, computed);
}
return computed;
}

public void clear() {
values.clear();
}
}
Loading

0 comments on commit 807477c

Please sign in to comment.