Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Work in progress] Command line tool refactor to run tests #241

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class XdkDistribution(project: Project): XdkProjectBuildLogic(project) {
val isCiEnabled = System.getenv(CI) == "true"
val currentOs: OperatingSystem = OperatingSystem.current()
val distributionTasks = listOf("distTar", "distZip", "withLaunchersDistTar", "withLaunchersDistZip")
val binaryLauncherNames = listOf("xcc", "xec")
val binaryLauncherNames = listOf("xcc", "xec", "xtc")

fun isDistributionArchiveTask(task: Task): Boolean {
return task.group == DISTRIBUTION_TASK_GROUP && task.name in distributionTasks
Expand Down
5 changes: 4 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ gradle-portal-publish = "1.2.1"
sonatype-publish = "2.0.0"
jakarta = "2.3.2"
rewrite-lib = "1.3.1"
jline="3.25.1"
jline = "3.25.1"
ktlint = "12.1.1"

[plugins]
Expand Down Expand Up @@ -57,17 +57,20 @@ xdk-oodb = { group = "org.xtclang", name = "lib-oodb", version.ref = "xdk" }
xdk-web = { group = "org.xtclang", name = "lib-web", version.ref = "xdk" }
xdk-webauth = { group = "org.xtclang", name = "lib-webauth", version.ref = "xdk" }
xdk-xenia = { group = "org.xtclang", name = "lib-xenia", version.ref = "xdk" }
xdk-xunit = { group = "org.xtclang", name = "lib-xunit", version.ref = "xdk" }

javatools = { group = "org.xtclang", name = "javatools", version.ref = "xdk" }
javatools-unicode = { group = "org.xtclang", name = "javatools-unicode", version.ref = "xdk" }
javatools-utils = { group = "org.xtclang", name = "javatools-utils", version.ref = "xdk" }
javatools-turtle = { group = "org.xtclang", name = "javatools-turtle", version.ref = "xdk" }
javatools-bridge = { group = "org.xtclang", name = "javatools-bridge", version.ref = "xdk" }

hamcrest = { module = "org.hamcrest:hamcrest", version = "2.2" }
javax-activation = { module = "com.sun.activation:javax.activation", version = "1.2.0" }
thegridman marked this conversation as resolved.
Show resolved Hide resolved
jakarta-xml-bind-api = { module = "jakarta.xml.bind:jakarta.xml.bind-api", version.ref = "jakarta" }
jaxb-runtime = { module = "org.glassfish.jaxb:jaxb-runtime", version.ref = "jakarta" }
jline = { module = "org.jline:jline", version.ref = "jline" }
mockito = { module = "org.mockito:mockito-core", version = "5.11.0" }

[bundles]
unicode = ["javax-activation", "jakarta-xml-bind-api", "jaxb-runtime"]
5 changes: 5 additions & 0 deletions javatools/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ plugins {
alias(libs.plugins.tasktree)
}

dependencies {
testImplementation(libs.hamcrest)
testImplementation(libs.mockito)
}

private val semanticVersion: SemanticVersion by extra

// TODO: Move these to common-plugins, the XDK composite build does use them in some different places.
Expand Down
20 changes: 19 additions & 1 deletion javatools/src/main/java/org/xvm/api/Connector.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,12 @@ public MainContainer getContainer()

/**
* Start the Runtime and the main Container.
* <p/>
* The injection map values must be either {@code String} or {@code String[]}.
*
* @param mapInjections (optional) a map of custom injections
*/
public void start(Map<String, String> mapInjections)
public void start(Map<String, ?> mapInjections)
{
if (!m_fStarted)
{
Expand All @@ -155,6 +159,20 @@ public void invoke0(String sMethodName, ObjectHandle... ahArg)
m_containerMain.invoke0(sMethodName, ahArg);
}

/**
* Invoke the test method with the specified arguments.
*
* @return {@code true} if XUnit was present to execute tests, otherwise {@code false}
*/
public boolean invokeTest0()
{
if (!m_fStarted)
{
throw new IllegalStateException("The container has not been started");
}
return m_containerMain.invokeTest0();
}

/**
* Wait for the container termination.
*/
Expand Down
3 changes: 3 additions & 0 deletions javatools/src/main/java/org/xvm/asm/ConstantPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,7 @@ public ByteConstant ensureNibbleConstant(int n)
public TypeConstant typeFPLiteral() {TypeConstant c = m_typeFPLiteral; if (c == null) {m_typeFPLiteral = c = ensureTerminalTypeConstant(clzFPLiteral() );} return c;}
public TypeConstant typeRegEx() {TypeConstant c = m_typeRegEx; if (c == null) {m_typeRegEx = c = ensureTerminalTypeConstant(clzRegEx() );} return c;}
public TypeConstant typeString() {TypeConstant c = m_typeString; if (c == null) {m_typeString = c = ensureTerminalTypeConstant(clzString() );} return c;}
public TypeConstant typeStringArray() {TypeConstant c = m_typeStringArray; if (c == null) {m_typeStringArray = c = ensureClassTypeConstant(clzArray(), null, typeString() );} return c;}
public TypeConstant typeStringable() {TypeConstant c = m_typeStringable; if (c == null) {m_typeStringable = c = ensureTerminalTypeConstant(clzStringable() );} return c;}
public TypeConstant typeStringBuffer() {TypeConstant c = m_typeStringBuffer; if (c == null) {m_typeStringBuffer = c = ensureTerminalTypeConstant(clzStringBuffer() );} return c;}
public TypeConstant typeBit() {TypeConstant c = m_typeBit; if (c == null) {m_typeBit = c = ensureTerminalTypeConstant(clzBit() );} return c;}
Expand Down Expand Up @@ -3966,6 +3967,7 @@ public static Auto withPool(ConstantPool pool) {
private transient TypeConstant m_typeFPLiteral;
private transient TypeConstant m_typeRegEx;
private transient TypeConstant m_typeString;
private transient TypeConstant m_typeStringArray;
private transient TypeConstant m_typeStringable;
private transient TypeConstant m_typeStringBuffer;
private transient TypeConstant m_typeString१;
Expand Down Expand Up @@ -4116,6 +4118,7 @@ private void optimize()
m_typeStringable = null;
m_typeStringBuffer = null;
m_typeString१ = null;
m_typeStringArray = null;
m_typeBit = null;
m_typeNibble = null;
m_typeBitArray = null;
Expand Down
12 changes: 12 additions & 0 deletions javatools/src/main/java/org/xvm/runtime/Container.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,19 @@ public <R> CompletableFuture<R> scheduleIO(Callable<R> task)
public MethodConstant findModuleMethod(String sMethod, ObjectHandle[] ahArg)
{
TypeInfo infoModule = getModule().getType().ensureTypeInfo();
return findModuleMethod(infoModule, sMethod, ahArg);
}

/**
* Find a module method to call.
*
* @param sMethod the name
* @param ahArg the arguments to pass to the method
*
* @return the method constant or null if not found
*/
public MethodConstant findModuleMethod(TypeInfo infoModule, String sMethod, ObjectHandle[] ahArg)
{
TypeConstant[] atypeArg;
if (ahArg.length == 0)
{
Expand Down
77 changes: 71 additions & 6 deletions javatools/src/main/java/org/xvm/runtime/MainContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,17 @@ public ObjectHandle getInjectable(Frame frame, String sName, TypeConstant type,
// check the custom injections
if (m_mapInjections != null)
{
String sValue = m_mapInjections.get(sName);
if (sValue != null && type.equals(frame.poolContext().typeString()))
Object oValue = m_mapInjections.get(sName);
if (oValue != null)
{
return xString.makeHandle(sValue);
if (type.equals(frame.poolContext().typeString()))
{
return xString.makeHandle(String.valueOf(oValue));
}
if (type.equals(frame.poolContext().typeStringArray()))
{
return xString.makeArrayHandle((String[]) oValue);
}
}
}
return null;
Expand All @@ -60,10 +67,12 @@ public ObjectHandle getInjectable(Frame frame, String sName, TypeConstant type,

/**
* Start the main container.
* <p/>
* The injection map values must be either {@code String} or {@code String[]}.
*
* @param (optional) a map of custom injections
* @param mapInjections (optional) a map of custom injections
*/
public void start(Map<String, String> mapInjections)
public void start(Map<String, ?> mapInjections)
{
if (m_contextMain != null)
{
Expand Down Expand Up @@ -131,8 +140,64 @@ public void invoke0(String sMethodName, ObjectHandle... ahArg)
}
}

/**
* Invoke the test entry point.
* <p/>
* The entry point for executing tests is the {@code test} method in "xunit.xtclang.org" module,
* not the module being tested.
*
* @return {@code true} if XUnit was present to execute tests, otherwise {@code false}
*/
public boolean invokeTest0()
{
try (var ignore = ConstantPool.withPool(f_idModule.getConstantPool()))
{
ConstantPool pool = ConstantPool.getCurrentPool();
ModuleConstant idXUnit = pool.ensureModuleConstant("xunit.xtclang.org");
if (idXUnit == null || idXUnit.getComponent() == null)
{
return false;
}

TypeInfo infoModule = idXUnit.getType().ensureTypeInfo();
MethodConstant idMethod = findModuleMethod(infoModule, "test", Utils.OBJECTS_NONE);
if (idMethod == null)
{
// we should not get here as we know there is the correct method in XUnit.
System.err.println("Missing: test method for " + idXUnit.getName());
return false;
}

TypeConstant typeModule = idXUnit.getType();
TypeComposition clzModule = resolveClass(typeModule);
CallChain chain = clzModule.getMethodCallChain(idMethod.getSignature());

FunctionHandle hInstantiateModuleAndRun = new NativeFunctionHandle((frame, ah, iReturn) ->
{
SingletonConstant idModule = frame.poolContext().ensureSingletonConstConstant(idXUnit);
ObjectHandle hModule = frame.getConstHandle(idModule);
ObjectHandle[] ahArg = new ObjectHandle[]{frame.getConstHandle(f_idModule)};

// TODO: ahArg[0] can also be deferred; need to safeguard that
return Op.isDeferred(hModule)
? hModule.proceed(frame, frameCaller ->
chain.invoke(frameCaller, frameCaller.popStack(), ahArg, Op.A_IGNORE))
: chain.invoke(frame, hModule, ahArg, Op.A_IGNORE);
});

m_contextMain.callLater(hInstantiateModuleAndRun, Utils.OBJECTS_NONE);
return true;
}
catch (Exception e)
{
throw new RuntimeException("failed to run: " + f_idModule, e);
}
}

/**
* Map of custom injections.
* <p/>
* The map values will either be {@code String} or {@code String[]}.
*/
private Map<String, String> m_mapInjections;
private Map<String, ?> m_mapInjections;
}
Original file line number Diff line number Diff line change
Expand Up @@ -377,21 +377,11 @@ protected void setSourceLocations(List<File> listSources)
m_listSources = listSources;
}

protected Version getVersion()
{
return m_version;
}

protected void setVersion(Version version)
{
m_version = version;
}

protected boolean isForcedRebuild()
{
return true;
}

protected Severity getSeverity()
{
return m_sevWorst;
Expand Down Expand Up @@ -431,10 +421,10 @@ protected String partialCompile(boolean fReenter)
}
else
{
File[] resourceDirs = options().getResourceLocation();
File fileOutput = options().getOutputLocation();
List<ModuleInfo> listTargets = selectTargets(options().getInputLocations(), resourceDirs, fileOutput);
boolean fRebuild = options().isForcedRebuild();
File[] resourceDirs = getResourceLocation();
File fileOutput = getOutputLocation();
List<ModuleInfo> listTargets = selectTargets(getInputLocations(), resourceDirs, fileOutput);
boolean fRebuild = isForcedRebuild();
checkErrors();

Map<File, Node> mapTargets = new ListMap<>(listTargets.size());
Expand Down Expand Up @@ -464,7 +454,7 @@ protected String partialCompile(boolean fReenter)
flushAndCheckErrors(allNodes);

// repository setup
repoLib = configureLibraryRepo(options().getModulePath());
repoLib = configureLibraryRepo(flags().getModulePath());
checkErrors();

if (cSystemModules == 0)
Expand Down Expand Up @@ -543,13 +533,6 @@ protected ModuleRepository configureResultRepo(File fileDest)
return m_repoResults = makeBuildRepo();
}

@Override
public void run()
{
// use partialRun() instead
throw new IllegalStateException();
}

@Override
protected void linkModules(org.xvm.compiler.Compiler[] compilers, ModuleRepository repo)
{
Expand Down Expand Up @@ -586,40 +569,27 @@ protected void abort(boolean fError)
// ----- Options adapter -------------------------------------------------------------------

@Override
protected Compiler.Options instantiateOptions()
public List<File> getInputLocations()
{
return new Options();
return CompilerAdapter.this.getSourceLocations();
}

/**
* A non-command-line Options implementation.
*/
class Options
extends Compiler.Options
@Override
public Version getVersion()
{
@Override
public List<File> getInputLocations()
{
return CompilerAdapter.this.getSourceLocations();
}

@Override
public Version getVersion()
{
return CompilerAdapter.this.getVersion();
}
return m_version;
}

@Override
public boolean isOutputFilenameQualified()
{
return true;
}
@Override
public boolean isOutputFilenameQualified()
{
return true;
}

@Override
public boolean isForcedRebuild()
{
return CompilerAdapter.this.isForcedRebuild();
}
@Override
public boolean isForcedRebuild()
{
return true;
}

// ----- fields ----------------------------------------------------------------------------
Expand Down
Loading