ScenarLang gives you access to the following kind of objects :
There is also a shortcut notation for objects that can be unmarsalled with jaxb
You can use these values/objects to :
Basic values are pretty much the same as there of Java :
::java
// A whole number writes
$WHOLE = 4;
// A decimal number writes
$DECIMAL = 4.5;
// A string
$STRING = "Some text";
// a boolean
$BOOLEAN = true;
$NULL = null;
Note : As a general rule, if you want to enforce a given type you need to add a type constraint which means you can specify the type after the keyword as.
::java
// here we make sure it is a Long
$SOME_LONG = 4 as "java.lang.Long";
To declare an array you should give a list of values separated by commas and square it with square-brackets.
::bash
$THIS_IS_AN_ARRAY = [ "one", "two", "three" ];
Collections are basically arrays with an extra type constraint on it : which means you declare an array list as such.
::bash
$LIST = [ "one", "two", "three" ] as "java.util.ArrayList";
Maps are a particuliar case of collection and therefore require a little extra syntax. Instead of just specifying objects, you need to specify associations. You can do so by putting a => sign between the key and the value.
::bash
// Note : using this syntax, the scenarlang runtime is able to infer that the type is Map.
// Note2: the key does not necessarily need to be a string, it can be any kind of value.
$MY_MAP = [ "key" => 43, "other_key" => mock "Person" ];
Instanciating a mock object is done via the mock keyword followed by a type name (or alias).
Limitation: you can only create a mock object for types that are not declared final.
::bash
$MOCK = mock "some.Class";
If ever in one of your test setups you need to gain access to one of your test resources, you can easily get a File reference to it using the keyword resource.
::java
$SOME_FILE = resource "/some/file/in/a/folder/file.txt";
There exists several kind of references :
We already talked about variables previously but if you skipped the beginning, here is a little refresh. Variables are declared and referenced in the same way : you simply prefix the variable name with a $ (dollar).
Variables can:
::bash
$THE_ANSWER = 42;
You can access the 'context' (the test class or alternatively a field from the test class that is annotated with @Context) fields directly via their name.
::java
public class MyTestClass {
private TestedType tested;
// ...
}
::java
// tested is actually the field coming from the previously defined test class
// Here we inject a value into the 'someService' field
// of the object 'tested' declared in our context.
tested.someService = mock "the.service.to.be.Mocked";
Accessing a field reference is done in the same way as in Java (and I already showed many examples that do so) : you simply specify the parent object name followed by a dot and the name of the child property.
Here is what it looks like :
::java
// sets a value in the 'child' field of the 'parent' object
parent.child = 42;
// it works ie for a variable too
$PARENT.child = 42;
You can access any static member of a class with the following syntax :
static "className" -> fieldname
::java
static "some.Class" -> instance = null;
$A = static "some.Class" -> doSomething();
~~~~~~~~~
### Function calls ###
Function calls use the same syntax as Java.
~~~~~~
::bash
$SOMETING = object.sub.something();
~~~~~~
## POJOS ##
ScenarLang let's you instanciate any POJO in a pretty expressive using a syntax close to that of JSON.
### Using the no-arg constructor ###
If you can afford to use the no-argument constructor (be it private), then you can use the simplified syntax which is: _**{ fieldname : fieldValue }**_ where fieldname : fieldValue can repeat at will (but need to be separated by a comma).
~~~~~~
::java
// This instanciate an object of the type "the.pojo.Type"
$A_POJO = {
someLong: 4,
someText: "text",
someFlag: true,
someArray: [ 3, 4, 5 ],
// Here you don't need to specify a type,
// the scenarlang runtime will infer it
// for you.
someNestedObject: {
someChildProp: "some child prop"
}
} as "the.pojo.Type";
~~~~~~
### Using a specific constructor ###
If you need to use a specific constructor or there is no default constructor, then you can use the longer syntax :
~~~~~~
::java
// This uses the 2 argument constructor defined in the class Person.
$A_PERSON = new ("the_name", "the_first_name") -> {
// If you want you can specify some fields with
// field : fieldValue
} as "Person";
~~~~~~
#### Notes : ####
* You are always setting **FIELDS**
* If you want to declare an object, it must start with { and finish with } (like in json).
* If you want to declare an array or collection, it must start with \[ and finish with \] (like in json).
* If you want to assign a type to a value, you use an 'as' clause : {} as "your.object.InnovativeType";
* If you set no type to a {} construct, you get a Map<String, Object>
* Types are inferred whenever possible so that you don't need to specify it for each and every field or value.
* You can instanciate a mock with the *mock "some.Type";* instruction.
* Properties in an object declaration or values in a collection are separated by commas
* When instanciating a pojo, the constructor part is optional as well as the type constraint but the **{}** are the minimal tokens required to instanciate an object.
## Interaction with JAXB ##
If you have an xml document that you could normally unmarshal with JaxWS/JaxB, then you don't need to rewrite your whole object using the scenar notation (that would be a waste of time). What you can do is simply use the follwing syntax :
~~~~~~~~~~~~~~
// resource file starts with a slash and will be looked up at the root of
// your jar (test-classes folder for maven users)
$MXL_REQUEST = jaxb from resource "/some/resource/file.xml" as "some_type";
// As usual, you can alter the content of the object loaded
// with jaxb using ScenarLang 'usual' syntax.
$XML_REQUEST.sub_field.sub_sub_field = "Hello world !";
~~~~~~~~~~~~~~
## Objects with a custom parser ##
This example was already detailed in the Step 1 in the paragraph about conversion configuration. You'll typically use a custom conversion when you want to instanciate a Date or an Enum. The following example shows an use case with an enum.
#### The java code ####
~~~~~~~
::java
public enum Guy {
ME, YOU, THEM;
/*
* It is IMHO a bad idea to place the annotation
* @ConversionMethod directly here because you normally
* don't want to embed ScenarLang direcly in your production
* binary.
*/
public static Guy fromString(String name){
if("ME".equals(name)) return ME;
if("YOU".equals(name)) return YOU;
if("THEM".equals(name)) return THEM;
return null;
}
}
public class GuyParser {
@ConversionMethod
public static Object guyFromString(String text){
return Guy.fromString(text);
}
}
~~~~~~~~~
#### The scn ####
::bash
parse "Guy" with "GuyParser";
$them = "THEM" as "Guy";
~~~~~~~~