Namespace definitions
The rell.test namespace is only accessible within test modules
Example
@test module;
function test() {
rell.test.block().run();
}
Since
0.10.4
Types
A test block builder; i.e. a builder for test blockchain blocks.
A test block consists of a list of test transactions that are executed when the block is built. A test transaction consists of a list of test operation calls, and a list of signing keypairs.
Test block timestamps
The timestamps of Rell test blocks are deterministic, and determined by the following rules:
If the next block's timestamp was set explicitly via
rell.test.set_next_block_time()
orrell.test.set_next_block_time_delta()
, that timestamp is used for the next block, and is then discarded (and will not be used by subsequent blocks).If the next block's timestamp was not set explicitly, and there is a previous block, the next block's timestamp is the timestamp of the previous block plus the block interval (
rell.test.block_interval
, which can be set withrell.test.set_block_interval()
).If the next block's timestamp was not set explicitly, and there is no previous block, the timestamp of the next (and first) block will be
2020-01-01 00:00:00 UTC
.
A test transaction builder; i.e. a builder for test transactions that comprise blockchain blocks.
A test transaction consists of a list of test operation calls, and a list of signing keypairs. The test transaction builder type has functions that facilitate straightforward transaction construction by passing operations and keys in various formats.
Properties
The time interval that will be used to determine the time of the next block to be built.
The next block to be built will have a timestamp equal to rell.test.last_block_time + rell.test.block_interval
unless it is explicitly set with rell.test.set_next_block_time()
or rell.test.set_next_block_time_delta()
.
Defaults to 10000
(10
seconds).
Can be modified with rell.test.set_block_interval()
.
The test keypair used to sign all blocks built in the test context.
Not secure - unsuitable for production usage.
The default value for the time interval between each block in the blockchain, in milliseconds. Equal to 10000
(10
seconds).
The default value for the timestamp of the first block in the blockchain, in milliseconds. Equal to 2020-01-01 00:00:00 UTC
, or 1577836800000
.
This is a Unix epoch timestamp, i.e. the number of milliseconds that have elapsed since midnight on 1st January 1970.
The timestamp of the most recently built block in the blockchain, in milliseconds.
This is a Unix epoch timestamp, i.e. the number of milliseconds that have elapsed since midnight on 1st January 1970.
The timestamp of the most recently built block in the blockchain, in milliseconds.
If there are no blocks in the blockchain (i.e. if the first block in the blockchain has yet to be built), this is null
.
If a value is present, it is a Unix epoch timestamp, i.e. the number of milliseconds that have elapsed since midnight on 1st January 1970.
The timestamp that the next block will have, once built, in milliseconds.
Equivalent to rell.test.last_block_time + rell.test.block_interval
(assuming there is at least one block in the blockchain).
This is a Unix epoch timestamp, i.e. the number of milliseconds that will have elapsed since midnight on 1st January 1970.
Functions
Assert two values are equal.
Assert that the given events were emitted during the construction of the last block, in the specified order.
Events are emitted in application code using op_context.emit_event()
.
Example - single event:
Application code
operation main() {
op_context.emit_event("my_message_type", "my_data".to_gtv());
}
Test code
function test_main() {
main().run();
// Assertion passes
rell.test.assert_events(("my_message_type", "my_data".to_gtv()));
}
function test_main_bad_1() {
main().run();
// Assertion fails - wrong message type
rell.test.assert_events(("other_message_type", "my_data".to_gtv()));
}
function test_main_bad_2() {
main().run();
// Assertion fails - wrong message content
rell.test.assert_events(("my_message_type", "other_data".to_gtv()));
}
Example - multiple events:
Application code
operation main() {
op_context.emit_event("my_message_type", "my_data".to_gtv());
op_context.emit_event("other_message_type", "other_data".to_gtv());
}
Test code
function test_main() {
main().run();
// Assertion passes
rell.test.assert_events(
("my_message_type", "my_data".to_gtv()),
("other_message_type", "other_data".to_gtv())
);
}
function test_main_bad() {
main().run();
// Assertion fails - event order incorrect
rell.test.assert_events(
("other_message_type", "other_data".to_gtv()),
("my_message_type", "my_data".to_gtv())
);
}
To assert a subset of events, or to assert independently of event order, use rell.test.get_events()
and make assertions over elements of the returned list.
Asserts a function fails; i.e. throws an exception.
Example
Application code
// This will throw a exception.
function bad(): integer {
return [0][1];
}
Test code
// This test will pass.
function test_bad() {
rell.test.assert_fails(bad(*));
}
Asserts a function fails; i.e. throws an exception; with a given exception message.
Verifies that the given exception message is a substring of the exception thrown by the given function (if thrown).
Example
Application code
// This will throw a exception.
function bad(): integer {
return [0][1];
}
Test code
// This test will pass.
function test_bad() {
rell.test.assert_fails("out of bounds", bad(*));
}
Assert a value is false
.
Prefer other assertion functions where possible, as they provide better error messages.
Assert that a value is greater than or equal to a given lower bound.
Assert that a value falls within given bounds.
Specifically, assert that the value is greater than or equal to a lower bound, and less than or equal to an upper bound.
Assert that a value falls within given bounds.
Specifically, assert that the value is greater than or equal to a lower bound, and less than an upper bound.
Assert that a value is greater than a given lower bound.
Assert that a value falls within given bounds.
Specifically, assert that the value is greater than a lower bound, and less than or equal to an upper bound.
Assert that a value falls within given bounds.
Specifically, assert that the value is greater than a lower bound, and less than an upper bound.
Assert that a value is less than or equal to a given upper bound.
Assert that a value is less than a given upper bound.
Assert two values are unequal.
Assert a value is not null
.
Assert a value is null
.
Assert a value is true
.
Prefer other assertion functions where possible, as they provide better error messages.
Get all events that were emitted during the construction of the last block.
Events are emitted in application code using op_context.emit_event()
.
Example:
Application code
op_context.emit_event("my_message_type", "my_gtv_data".to_gtv());
op_context.emit_event("my_other_message_type", "my_gtv_data".to_gtv());
op_context.emit_event("my_another_message_type", "my_gtv_data".to_gtv());
Test code
// returns: [(my_message_type,"my_gtv_data"), (my_other_message_type,"my_gtv_data"), (my_another_message_type,"my_gtv_data")]
return rell.test.get_events();
Create a no-op test operation call.
The zero-argument rell.test.nop()
is effectively an alias of rell.test.nop(x: integer)
where a unique integer argument x
is passed each time, serving the purpose of distinguishing transactions that are identical except for the presence of a nop
call.
Example:
Illegal
rell.test.tx().op(my_op).run();
rell.test.tx().op(my_op).run(); // Not allowed; all transactions must be unique!
Legal
// Ok, the transactions are distinct since each nop automatically uses a different nonce.
rell.test.tx().op(my_op).op(rell.test.nop()).run();
rell.test.tx().op(my_op).op(rell.test.nop()).run();
Create a no-op test operation call.
Serves the purpose of distinguishing transactions that are identical except for the presence of a nop
call.
rell.test.nop(x)
is equivalent to rell.test.op('nop', x.to_gtv())
, which is a test operation call to the predefined operation:
operation nop(v: gtv) {}
Example:
Illegal
rell.test.tx().op(my_op).op(rell.test.nop(x'00')).run();
rell.test.tx().op(my_op).op(rell.test.nop(x'00')).run(); // Not allowed; all transactions must be unique!
Legal
rell.test.tx().op(my_op).op(rell.test.nop(x'00')).run();
rell.test.tx().op(my_op).op(rell.test.nop(x'01')).run(); // Ok, since the transactions are distinct.
Create a no-op test operation call.
Serves the purpose of distinguishing transactions that are identical except for the presence of a nop
call.
rell.test.nop(x)
is equivalent to rell.test.op('nop', x.to_gtv())
, which is a test operation call to the predefined operation:
operation nop(v: gtv) {}
Example:
Illegal
rell.test.tx().op(my_op).op(rell.test.nop(0)).run();
rell.test.tx().op(my_op).op(rell.test.nop(0)).run(); // Not allowed; all transactions must be unique!
Legal
rell.test.tx().op(my_op).op(rell.test.nop(0)).run();
rell.test.tx().op(my_op).op(rell.test.nop(1)).run(); // Ok, since the transactions are distinct.
Create a no-op test operation call.
Serves the purpose of distinguishing transactions that are identical except for the presence of a nop
call.
rell.test.nop(x)
is equivalent to rell.test.op('nop', x.to_gtv())
, which is a test operation call to the predefined operation:
operation nop(v: gtv) {}
Example:
Illegal
rell.test.tx().op(my_op).op(rell.test.nop("a")).run();
rell.test.tx().op(my_op).op(rell.test.nop("a")).run(); // Not allowed; all transactions must be unique!
Legal
rell.test.tx().op(my_op).op(rell.test.nop("a")).run();
rell.test.tx().op(my_op).op(rell.test.nop("z")).run(); // Ok, since the transactions are distinct.
Set the time interval between future blocks in the blockchain, in milliseconds.
If the timestamp for the next block has been explicitly set by calling rell.test.set_next_block_time()
or `rell.test.set_next_block_time_delta(), the new interval does not take effect until after the next block.
Set the timestamp that the next block will have, once built, in milliseconds.
time
is a Unix epoch timestamp, i.e. the number of milliseconds that will have elapsed since midnight on 1st January 1970.
Set the timestamp that the next block will have, once built, relative to the previous block, in milliseconds.
Calling rell.time.set_next_block_time_delta(x)
means the next block will have timestamp x
milliseconds after the timestamp of the previous block.
rell.test.set_next_block_time_delta(delta)
is equivalent to rell.test.set_next_block_time(rell.test.last_block_time + delta)
if there is a previous block. Otherwise, this does nothing.