Creating a ceylon.test.TestRunner

62 Views Asked by At

I'm trying to create a test suite that I can run programmatically. (The documentation does mention that one can tease an IDE into doing the test running, but it seems to me a more regular approach to set up the test suite as a standard Ceylon module that has its own runnable unit. Also, the documentation doesn't say anything about how to actually do it the IDE way).

So, I'm creating a TestRunner using the createTestRunner function. Said function takes a Sequential of TestSources ('TestSource[]') as its first argument. TestSource is an alias for this type:

Module|Package|ClassDeclaration|FunctionDeclaration|Class<Anything,Nothing>|FunctionModel<Anything,Nothing>|String

Which promts the question: How do I want to feed my tests to the test runner?

For starters it seems easiest to put them in local functions and then let the test runner access these functions somehow (not further specified). As the long list of types that are included in the TestSource alias doesn't seem to include actual Functions, I tried to go for the nearest candidate that looked like the right thing: FunctionDeclaration.

In order to make such a function declaration, I first had to ponder how my test wrapper functions might actually look like. Perhaps something like this?

Anything myTests1 () {
    // assert something!
    return null;
}

void myTests2 () {
    // assert some more things!
}

(these functions are typewise equivalent, by the way)

After a lot of Ceylon Herd scrutiny, I figured that a FunctionDeclaration for such functions could be spelled out like this:

// function name for function declaration:
LIdentifier funName = LIdentifier("myName");

// type of return value for function declaration:
UIdentifier returnTypeName1 = UIdentifier("Anything");
TypeNameWithTypeArguments returnTypeName2 = TypeNameWithTypeArguments(returnTypeName1);
BaseType returnType = BaseType( returnTypeName2 );

// type of parameters for function declaration:
Sequential<Parameter> parameters1 = [];  // our test wrapper functions takes no arguments
Parameters parameters2 = Parameters( parameters1 );
Sequence<Parameters> parameterLists = [parameters2];

// the actual function declaration:
FunctionDeclaration myFunctionDeclaration = FunctionDeclaration(
    funName,
    returnType,
    parameterLists
);

So now, all I had to do was to feed this to the createTestRunner function. I just had to put myFunctionDeclaration into a TestSource[]:

TestSource myTestSource = myFunctionDeclaration;
TestSource[] mySourceList = [myTestSource];
TestRunner myTestRunner = createTestRunner(mySourceList);

But that first line doesn't work. myFunctionDeclaration of type 'FunctionDeclaration' simply doesn't pass as a TestSource type. Why not? Is FunctionDeclaration not a proper TestSource type? Looking at the alias definition for TestSource, FunctionDeclaration seems to be right there in the list of possible types:

Module|Package|ClassDeclaration|FunctionDeclaration|Class<Anything,Nothing>|FunctionModel<Anything,Nothing>|String

What am I missing here?

1

There are 1 best solutions below

3
On BEST ANSWER

This is a FunctionDeclaration literal:

`function myTests1`

(As opposed to a Function, which is `myTests1` without the keyword. The first is a detyped model in ceylon.language.meta.declaration, the second a statically typed model in ceylon.language.meta.model. See Tour, The metamodel.)

So I think what you’re supposed to do for test runners is:

value myTestRunner = createTestRunner([`function myTests1`, `function myTests2`]);

(But I’ve never done that myself.)

What you found on Herd is ceylon.ast, a completely unrelated set of modules that lets you describe Ceylon source code. Your myFunctionDeclaration describes the Abstract Syntax Tree of the function

Anything myName();

but only at the syntax level: the function is never compiled. You don’t need ceylon.ast for metamodel stuff. (Note also that this is a function declaration, not a function definition. It’s syntactically valid, but won’t be accepted by the typechecker because it’s not annotated formal.)

As a side note, the ceylon.ast.create module offers much more convenient ways to instantiate ceylon.ast.core nodes (instead of using that module directly, as you did):

value fun = functionDefinition {
    name = "myName";
    type = baseType("Anything");
};