Skip to content

Commit

Permalink
Assertion with ceylon.promise::Promise
Browse files Browse the repository at this point in the history
  • Loading branch information
LisiLisenok committed Mar 9, 2016
1 parent 1ec2d72 commit 32d3a6a
Show file tree
Hide file tree
Showing 27 changed files with 590 additions and 300 deletions.
28 changes: 16 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#### asyncTest
is an extension to SDK `ceylon.test` module with following capabilities:
* testing asynchronous multithread code
* common initialization for a set of test functions
* storing initialized values on test context and retrieving them during test execution
* executing tests concurrently or sequentially
* parameterized testing
* conditional test execution
* organizing complex test conditions into a one flexible expression with matchers
* multi-reporting, i.e. several failures or successes can be reported for a one particular test execution (test function)
* reporting test results using charts (or graphs)

* testing asynchronous multithread code
* common initialization for a test suite
* controlling test execution order
* executing tests concurrently or sequentially
* parameterized testing
* conditional test execution
* organizing complex test conditions into a one flexible expression with matchers
* multi-reporting: several failures or successes can be reported for a one particular test execution (test function),
each report is represented as test variant and might be marked with `String` title
* reporting test results using charts (or graphs)


The module is available on [CeylonHerd](https://herd.ceylon-lang.org/modules/herd.asynctest).


Expand All @@ -24,14 +26,15 @@ Available on JVM only
* ceylon.collection/1.2.1
* ceylon.file/1.2.1
* ceylon.language/1.2.1
* ceylon.promise/1.2.1 shared
* ceylon.test/1.2.1 shared
* java.base/8 JDK


#### Usage and documentation

The extension is aimed to be run using Ceylon test tool.
See usage details in [API documentation](https://modules.ceylon-lang.org/repo/1/herd/asynctest/0.4.0/module-doc/api/index.html).
See usage details in [API documentation](https://modules.ceylon-lang.org/repo/1/herd/asynctest/0.5.0/module-doc/api/index.html).


#### Examples
Expand All @@ -41,4 +44,5 @@ See usage details in [API documentation](https://modules.ceylon-lang.org/repo/1/
* [Time scheduler](examples/herd/examples/asynctest/scheduler) testing.
* [Microbenchmark](examples/herd/examples/asynctest/mapperformance) -
comparative performance test of Ceylon / Java HashMap and TreeMap.
* [Matchers](examples/herd/examples/asynctest/matchers) - mathcers usage.
* [Matchers](examples/herd/examples/asynctest/matchers) - matchers usage.
* [Maintainer](examples/herd/examples/asynctest/maintainer) - controlling test execution order.
145 changes: 72 additions & 73 deletions examples/herd/examples/asynctest/fibonacci/fibonacci.ceylon
Original file line number Diff line number Diff line change
@@ -1,75 +1,74 @@
import ceylon.promise {
import ceylon.promise {

Deferred,
Promise
}
import java.lang {
Deferred,
Promise
}
import java.lang {

Runnable,
Thread
}

"Calculates Fibonacci number by its index.
"
throws( `class AssertionError`, "passed index of Fibonacci number `indexOfFibonacciNumber` is less or equals to zero" )
shared Integer positiveFibonacciNumber( Integer indexOfFibonacciNumber ) {
"Fibonnachi number index must be positive"
assert ( indexOfFibonacciNumber > 0 );
variable Integer n0 = 0;
variable Integer n1 = 1;
variable Integer ret = 1;
variable Integer currentIndex = 1;
while ( currentIndex < indexOfFibonacciNumber ) {
ret = n0 + n1;
n0 = n1;
n1 = ret;
currentIndex ++;
}
return ret;
}

"Calculates index of positive Fibonacci number. That's may not be correct for index 1 and 2,
which corresponds to equals Fibonacci numbers."
throws( `class AssertionError`, "passed `fibonacciNumber` is not a Fibonacci number" )
shared Integer fibonacciNumberIndex( Integer fibonacciNumber ) {
"fibonacci number must be positive"
assert ( fibonacciNumber > 0 );
variable Integer n0 = 0;
variable Integer n1 = 1;
variable Integer ret = 1;
variable Integer currentIndex = 1;
while ( ret < fibonacciNumber ) {
ret = n0 + n1;
n0 = n1;
n1 = ret;
currentIndex ++;
}
"passed `fibonacciNumber` is not a Fibonacci number"
assert ( ret == fibonacciNumber );
return currentIndex;
}


"Calculates Fibonacci number by its index in separated thread and returns result as promise.
This is function to be tested."
shared Promise<Integer> asyncPositiveFibonacciNumber( Integer indexOfFibonacciNumber ) {
Deferred<Integer> ret = Deferred<Integer>();

Thread th = Thread (
object satisfies Runnable {
shared actual void run() {
try {
ret.fulfill( positiveFibonacciNumber( indexOfFibonacciNumber ) );
}
catch ( Throwable err ) {
ret.reject( err );
}
}
}
);
th.start();

return ret.promise;
}

Runnable,
Thread
}

"Calculates Fibonacci number by its index.
Function returns incorrect result in order to demonstrate test framework output.
"
throws( `class AssertionError`, "passed index of Fibonacci number `indexOfFibonacciNumber` is less or equals to zero" )
shared Integer positiveFibonacciNumber( Integer indexOfFibonacciNumber ) {
"Fibonnachi number index must be positive"
assert ( indexOfFibonacciNumber > 0 );
variable Integer n0 = 0;
variable Integer n1 = 1;
variable Integer ret = 1;
variable Integer currentIndex = 0; // use 1 to succeed the test!
while ( currentIndex < indexOfFibonacciNumber ) {
ret = n0 + n1;
n0 = n1;
n1 = ret;
currentIndex ++;
}
return ret;
}

"Calculates index of positive Fibonacci number. That's may not be correct for index 1 and 2,
which corresponds to equals Fibonacci numbers."
throws( `class AssertionError`, "passed `fibonacciNumber` is not a Fibonacci number" )
shared Integer fibonacciNumberIndex( Integer fibonacciNumber ) {
"fibonacci number must be positive"
assert ( fibonacciNumber > 0 );
variable Integer n0 = 0;
variable Integer n1 = 1;
variable Integer ret = 1;
variable Integer currentIndex = 1;
while ( ret < fibonacciNumber ) {
ret = n0 + n1;
n0 = n1;
n1 = ret;
currentIndex ++;
}
"passed `fibonacciNumber` is not a Fibonacci number"
assert ( ret == fibonacciNumber );
return currentIndex;
}


"Calculates Fibonacci number by its index in separated thread and returns result as promise.
This is function to be tested."
shared Promise<Integer> asyncPositiveFibonacciNumber( Integer indexOfFibonacciNumber ) {
Deferred<Integer> ret = Deferred<Integer>();

Thread th = Thread (
object satisfies Runnable {
shared actual void run() {
try {
ret.fulfill( positiveFibonacciNumber( indexOfFibonacciNumber ) );
}
catch ( Throwable err ) {
ret.reject( err );
}
}
}
);
th.start();

return ret.promise;
}

57 changes: 16 additions & 41 deletions examples/herd/examples/asynctest/fibonacci/fibonacciTest.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import herd.asynctest {
}
import herd.asynctest.match {

EqualTo
EqualTo,
Mapping,
MatchResult
}


"Fibonnachi test parameters."
"Fibonacci test parameters."
see( `function runFibonacciTest` )
{[Integer, Integer]*} fibonacciNumbers =>
{
Expand All @@ -26,55 +28,28 @@ see( `function runFibonacciTest` )
"Runs test of Fibonacci numbers calculations.
Testing:
* comparison of expected value to calculated one
* comparison of calculated index of Fibonacci number with passed one - this will fail if pass index `2`
* comparison of calculated index of Fibonacci number with passed one - this will fail if pass index of `2`
The function is marked with `testExecutor` annotation in order to perform asynchronous test.
Alternatively `testExecutor` annotation can be used at module level."
test parameters( `value fibonacciNumbers` )
testExecutor( `class AsyncTestExecutor` )
shared void runFibonacciTest (
"Context to send test results." AsyncTestContext context,
"Index of fibonnachi number to be calculated." Integer indexOfFibonacciNumber,
"Index of Fibonacci number to be calculated." Integer indexOfFibonacciNumber,
"Expected results of the calculations." Integer expectedFibonacciNumber
) {
// starts testing on context
// start testing on context
context.start();

// do testing procedure
asyncPositiveFibonacciNumber( indexOfFibonacciNumber ).completed (
( Integer calculatedFibonacciNumber ) {
// compare calculated and expected values and notify context if fails
// Don't use `ceylon.test.assert...` here. It will throw on separated thread and will cause abnormal program termination
context.assertThat (
calculatedFibonacciNumber,
EqualTo( expectedFibonacciNumber ),
"number equality"
);

// calculates index from resulting Fibonacci number and compare it with passed one
try {
value index = fibonacciNumberIndex( calculatedFibonacciNumber );
context.assertThat (
index,
EqualTo( indexOfFibonacciNumber ),
"index equality"
);
}
catch ( Throwable err ) {
context.fail( err );
}

// completes the test when results reported
context.complete( "Fibonacci number is ``calculatedFibonacciNumber``" );
},
( Throwable reason ) {
// fail the test with error
// Don't use `ceylon.test.fail` here. It will throw on separated thread and will cause abnormal program termination
context.fail( reason );
// completes the test when fail reported
context.complete();
}
);
// perform calculation and checking
context.assertThat<Integer> (
asyncPositiveFibonacciNumber( indexOfFibonacciNumber ),
EqualTo( expectedFibonacciNumber ).and( Mapping( fibonacciNumberIndex, EqualTo( indexOfFibonacciNumber ) ) ),
"",
true
).onComplete( ( MatchResult|Throwable res ) => context.complete() );

// just return whithout completion - the test will be completed later when promise is resolved
// just return whithout completion
// the test will be completed later when promise returned by `asyncPositiveFibonacciNumber` is resolved
}
13 changes: 6 additions & 7 deletions examples/herd/examples/asynctest/fibonacci/package.ceylon
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"
Testing of asynchronous calculation of Fibonacci numbers.
Test is performed on [[asyncPositiveFibonacciNumber]] using [[runFibonacciTest]] test function.
>Function [[positiveFibonacciNumber]] returns incorrect results in order to demonstrate test framework output.
"
by( "Lis" )
shared package herd.examples.asynctest.fibonacci;
"
Testing of asynchronous calculation of Fibonacci numbers.
Test is performed on [[asyncPositiveFibonacciNumber]] using [[runFibonacciTest]] test function.
"
by( "Lis" )
shared package herd.examples.asynctest.fibonacci;
4 changes: 2 additions & 2 deletions examples/herd/examples/asynctest/maintainer/Extremum.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ shared class Extremum()
test parameters( `value minimumInput` )
shared void minWithExpected( AsyncTestContext context, {Integer*} stream, Integer expected ) {
context.start();
context.assertThat( min( stream ), PassExisted( EqualObjects( expected ) ) );
context.assertThat( min( stream ), PassExisted( EqualObjects( expected ) ), "", true );
context.complete();
}

Expand All @@ -56,7 +56,7 @@ shared class Extremum()
test parameters( `value maximumInput` )
shared void maxWithExpected( AsyncTestContext context, {Integer*} stream, Integer expected ) {
context.start();
context.assertThat( max( stream ), PassExisted( EqualObjects( expected ) ) );
context.assertThat( max( stream ), PassExisted( EqualObjects( expected ) ), "", true );
context.complete();
}

Expand Down
4 changes: 3 additions & 1 deletion examples/herd/examples/asynctest/maintainer/Sorter.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ shared class Sorter()
test parameters( `function generateSortInput` )
shared void sortWithExpected( AsyncTestContext context, SortInput input ) {
context.start();
context.assertThat( input.input.sort( increasing<Integer> ), EqualObjects( input.expected ), input.string );
context.assertThat (
input.input.sort( increasing<Integer> ), EqualObjects( input.expected ), input.string, true
);
context.complete();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,8 @@ sequential class CeylonJavaMapMicrobenchmark() satisfies TestSuite

shared actual void dispose() {
plotReporter.report (
[
putChart.build(), getChart.build(), removeChart.build(),
hashMapRatioChart.build(), treeMapRatioChart.build()
]
putChart.build(), getChart.build(), removeChart.build(),
hashMapRatioChart.build(), treeMapRatioChart.build()
);
}

Expand Down Expand Up @@ -296,9 +294,9 @@ sequential class CeylonJavaMapMicrobenchmark() satisfies TestSuite
String getRatioStr = formatFloat( getRatio, 2, 2 );
String removeRatioStr = formatFloat( removeRatio, 2, 2 );

context.assertThat( putRatio, LessOrEqual( 1.0 + tolerance ), "'put' Ceylon / Java ratio" );
context.assertThat( getRatio, LessOrEqual( 1.0 + tolerance ), "'get' Ceylon / Java ratio" );
context.assertThat( removeRatio, LessOrEqual( 1.0 + tolerance ), "'remove' Ceylon / Java ratio" );
context.assertThat( putRatio, LessOrEqual( 1.0 + tolerance ), "'put' Ceylon / Java ratio", true );
context.assertThat( getRatio, LessOrEqual( 1.0 + tolerance ), "'get' Ceylon / Java ratio", true );
context.assertThat( removeRatio, LessOrEqual( 1.0 + tolerance ), "'remove' Ceylon / Java ratio", true );

putPlotter.addPoint( totalItems.float, putRatio );
getPlotter.addPoint( totalItems.float, getRatio );
Expand Down
Loading

0 comments on commit 32d3a6a

Please sign in to comment.