Skip to content

Commit

Permalink
Merge pull request #727 from lf-lang/cpp-tests-missing
Browse files Browse the repository at this point in the history
Port more C tests to Cpp
  • Loading branch information
cmnrd authored Dec 15, 2021
2 parents d386a4d + bf84399 commit b2f770e
Show file tree
Hide file tree
Showing 18 changed files with 745 additions and 0 deletions.
27 changes: 27 additions & 0 deletions test/Cpp/src/ActionIsPresent.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Tests the is_present variable for actions in cpp
target Cpp;

main reactor ActionIsPresent(offset:time(1 nsec), period:time(500 msec)) {
logical action a;
state success:bool(false);
state zero:time(0 nsec);
reaction(startup, a) -> a {=
if (!a.is_present()) {
if (offset == zero) {
std::cout << "Hello World!" << '\n';
success = true;
} else {
a.schedule(offset);
}
} else {
std::cout << "Hello World 2!" << '\n';
success = true;
}
=}
reaction(shutdown) {=
if (!success) {
std::cerr << "Failed to print 'Hello World!'" << '\n';
exit(1);
}
=}
}
100 changes: 100 additions & 0 deletions test/Cpp/src/Alignment.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// This test checks that the downstream reaction is not invoked more
// than once at a logical time.
target Cpp {
logging: LOG,
timeout: 1 sec,
build-type: Debug
}

reactor Source {
output out:int;
state count:int(1);
timer t(0, 100 msec);
reaction(t) -> out {=
count++;
out.set(count);
=}
}

reactor Sieve {
private preamble {=
#include "reactor-cpp/logging.hh"
=}
input in:int;
output out:bool;
state primes:std::vector<int>;
reaction(startup) {=
// There are 1229 primes between 1 and 10,000.
// Primes 1 and 2 are not on the list.
primes.push_back(3);
=}
reaction(in) -> out {=
// Reject out of bounds inputs
if(*in.get() <= 0 || *in.get() > 10000) {
reactor::log::Warn() << "Sieve: Input value out of range: " << *in.get();
}
// Primes 1 and 2 are not on the list.
if (*in.get() == 1 || *in.get() == 2) {
out.set(true);
return;
}
// If the input is greater than the last found prime, then
// we have to expand the list of primes before checking to
// see whether this is prime.
int candidate = primes.back();
reactor::log::Info() << "Sieve: Checking prime: " << candidate;
while (*in.get() > primes.back()) {
candidate += 2;
bool prime = true;
for (auto i : primes) {
if(candidate % i == 0) {
// Candidate is not prime. Break and add 2 by starting the loop again
prime = false;
break;
}
}
// If the candidate is not divisible by any prime in the list, it is prime
if (prime) {
primes.push_back(candidate);
reactor::log::Info() << "Sieve: Found prime: " << candidate;
}
}

// We are now assured that the input is less than or
// equal to the last prime on the list.
// See whether the input is an already found prime.
// Search the primes from the end, where they are sparser.
for (auto i = primes.rbegin(); i != primes.rend(); ++i) {
if(*i == *in.get()) {
out.set(true);
return;
}
}
=}
}

reactor Destination {
input ok:bool;
input in:int;
state last_invoked:{=reactor::TimePoint=};
reaction(ok, in) {=
if (ok.is_present() && in.is_present()) {
reactor::log::Info() << "Destination: Input " << *in.get() << " is a prime at logical time ( "
<< get_elapsed_logical_time() << " )";
}
if( get_logical_time() <= last_invoked) {
reactor::log::Error() << "Invoked at logical time (" << get_logical_time() << ") "
<< "but previously invoked at logical time (" << get_elapsed_logical_time() << ")";
}

last_invoked = get_logical_time();
=}
}
main reactor {
source = new Source();
sieve = new Sieve();
destination = new Destination();
source.out -> sieve.in;
sieve.out -> destination.ok;
source.out -> destination.in;
}
30 changes: 30 additions & 0 deletions test/Cpp/src/CompositionGain.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// This tests send data through a contained reactor
target Cpp;
reactor Gain {
input gainin:int;
output y:int;
reaction(gainin) -> y {=
reactor::log::Info() << "Gain received " << *gainin.get();
y.set(*gainin.get()*2);
=}
}
reactor Wrapper {
input x:int;
output y:int;
gain = new Gain();
x -> gain.gainin;
gain.y -> y;
}
main reactor CompositionGain {
wrapper = new Wrapper();
reaction(startup) -> wrapper.x {=
wrapper.x.set(42);
=}
reaction(wrapper.y) {=
reactor::log::Info() << "Received " << *wrapper.y.get();
if (*wrapper.y.get() != 42*2) {
reactor::log::Error() << "Received value should have been " << 42 * 2;
exit(2);
}
=}
}
54 changes: 54 additions & 0 deletions test/Cpp/src/DoubleInvocation.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// This illustrates a very strange bug that showed up
// and has now been fixed. This test ensures it does
// not reappear.
// At logical time zero, the two Print reactors used to be
// fired twice each at the same logical time.
// They should only be fired once.
// This behavior was oddly eliminated by either of the following
// actions, neither of which should affect this behavior:
// * Removing the startup reaction in Print.
// * Sending only position, not velocity from Ball.
// (copied from the c version of the test)

target Cpp{
timeout: 5 sec,
fast: true
}
reactor Ball {
output position:int;
output velocity:int;
state p:int(200);
timer trigger(0, 1 sec);
reaction(trigger) -> position, velocity {=
position.set(p);
velocity.set(-1);
p -= 1;
=}
}
reactor Print {
input velocity:int;
input position:int;
state previous:int(-1);
reaction (startup) {=
reactor::log::Info() << "####### Print startup";
=}
reaction (position, velocity) {=
if (position.is_present()) {
reactor::log::Info() << "Position: " << *position.get();
}
if (*position.get() == previous) {
reactor::log::Error() << "Multiple firings at the same logical time!";
exit(1);
}
=}

}
main reactor DoubleInvocation {
b1 = new Ball();
p = new Print();
plot = new Print();
b1.position -> p.position;
b1.velocity -> p.velocity;
b1.position -> plot.position;
b1.velocity -> plot.velocity;
}
61 changes: 61 additions & 0 deletions test/Cpp/src/DoublePort.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Test the case where two upstream reactors
* pass messages to a downstream reactor on two
* different ports. One message carries
* a microstep delay relative to the other.
*
* @author Maiko Brants
*/
target Cpp {
timeout: 900 msec,
fast: true
};

import Count from "lib/Count.lf";

reactor CountMicrostep {
state count:int(1);
output out:int;
logical action act:int;
timer t(0, 1 sec);
reaction(t) -> act {=
act.schedule( count);
count++;
=}

reaction(act) -> out {=
out.set(act.get());
=}
}

reactor Print {
input in:int;
input in2:int;
reaction(in, in2) {=
if(in.is_present()){
reactor::log::Info() << "At tag (" << get_elapsed_logical_time() << ", " << environment()->logical_time().micro_step()
<< "), received in = " << *in.get();
} else if (in2.is_present()){
reactor::log::Info() << "At tag (" << get_elapsed_logical_time() << ", " << environment()->logical_time().micro_step()
<< "), received in2 = " << *in2.get();
}


if ( in.is_present() && in2.is_present()) {
reactor::log::Error() << "ERROR: invalid logical simultaneity.";
exit(1);
}
=}

reaction(shutdown) {=
reactor::log::Info() << "SUCCESS: messages were at least one microstep apart.";
=}
}

main reactor DoublePort {
c = new Count();
cm = new CountMicrostep();
p = new Print();
c.c -> p.in;
cm.out -> p.in2;
}
42 changes: 42 additions & 0 deletions test/Cpp/src/ImportComposition.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
*
* @author Maiko Brants TU Dresden
*
* This tests the ability to import a reactor definition
* that itself imports a reactor definition.
*
* modeled after the C version of this test
**/
target Cpp;
import ImportedComposition from "lib/ImportedComposition.lf";

main reactor ImportComposition {
public preamble {=
#include "reactor-cpp/logging.hh"
=}

imp_comp = new ImportedComposition();
state received:bool(false);
reaction(startup) -> imp_comp.x {=
imp_comp.x.set(42);
=}
reaction(imp_comp.y) {=
auto receive_time = get_elapsed_logical_time();
reactor::log::Info() << "Received " << *imp_comp.y.get() << " at time " << receive_time;
received = true;
if(receive_time != 55ms) {
reactor::log::Error() << "ERROR: Received time should have been: 55,000,000.";
exit(1);
}
if(*imp_comp.y.get() != 42*2*2) {
reactor::log::Error() << "ERROR: Received value should have been: " << 42*2*2 << ".";
exit(2);
}
=}
reaction(shutdown) {=
if(!received){
reactor::log::Error() << "ERROR: Nothing received.";
exit(3);
}
=}
}
23 changes: 23 additions & 0 deletions test/Cpp/src/ImportRenamed.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
*
* @author Maiko Brants TU Dresden
*
* This tests the ability to import a reactor definition
* that itself imports a reactor definition.
*
* modeled after the C version of this test
**/
target Cpp;
import Imported as X from "lib/Imported.lf"
import Imported as Y from "lib/Imported.lf"
import ImportedAgain as Z from "lib/ImportedAgain.lf"
main reactor {
timer t;
a = new X();
b = new Y();
c = new Z();

reaction(t) -> a.x {=
a.x.set(42);
=}
}
28 changes: 28 additions & 0 deletions test/Cpp/src/ParameterHierarchy.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
*
* @author Maiko Brants TU Dresden
*
* Test that parameter values pass down a deep hierarchy.
*
* modeled after the C version of this test
**/
target Cpp;
reactor Deep(p:int(0)) {
reaction(startup) {=
if(p != 42) {
reactor::log::Error() << "Parameter value is: " << p << ". Should have been 42.";
exit(1);
} else {
reactor::log::Info() << "Success.";
}
=}
}
reactor Intermediate(p:int(10)) {
a = new Deep(p = p);
}
reactor Another(p:int(20)) {
a = new Intermediate(p = p);
}
main reactor ParameterHierarchy {
a = new Intermediate(p = 42);
}
Loading

0 comments on commit b2f770e

Please sign in to comment.