Skip to content

add test_scheduler to support marble tests#1665

Open
kirkshoop wants to merge 55 commits intoNVIDIA:mainfrom
kirkshoop:marbletesting
Open

add test_scheduler to support marble tests#1665
kirkshoop wants to merge 55 commits intoNVIDIA:mainfrom
kirkshoop:marbletesting

Conversation

@kirkshoop
Copy link
Contributor

test_context implements a time-scheduler with additional test features.

test_context is used to build tests using marble sequence senders
and marble recorders

test_clock_context & test_clock are used to represent time for the tests

test_scheduler is used to queue tasks on the test_context at virtual-time points

One or more __test_sequence(s) are constructed from marble
diagrams and each schedules marbles on the test_scheduler
when connected and started

Once one or more __test_sequence(s) have been composed into an expression,
the test_context is used to record the expression results as a
set of marbles. To support the testing of infinite sequences
the recording will be requested to stop at a default of 1000ms from
start() if the expression has not completed.

The expression result marbles are then compared to an expected
set of marbles generated from a separate marble diagram

An example of usage:

TEST_CASE(
"test_scheduler - test_context marble-sequence never",
"[sequence_senders][test_scheduler]") {
  test_context __test{};
  auto __clock = __test.get_clock();
  CHECK(test_clock::time_point{0ms} == __clock.now());

  // a sequence that will produce '0' at 1ms from start()
  // and then never complete
  auto __sequence = __test.get_marble_sequence_from(
    "  -0-"_mstr);

  // the set of marbles for a sequence that contains '5'
  // at 1ms from start() and then is externally stopped
  // after 1000ms have elapsed since start()
  auto expected = get_marbles_from(__clock,
    "=^-5 998ms $"_mstr);

  // record an expression that is expected to turn '0' to '5'
  auto actual = __test.get_marbles_from(
                       __sequence
                       | then_each([](char c){ return c+5; }));

  CHECK(test_clock::time_point{1000ms} == __clock.now());
  CAPTURE(__sequence.__marbles_);
  CHECK(expected == actual);
}

with output:

-------------------------------------------------------------------------------
test_scheduler - test_context marble-sequence never
-------------------------------------------------------------------------------
/home/coder/stdexec/test/exec/sequence/test_test_scheduler.cpp:114
...............................................................................

/home/coder/stdexec/test/exec/sequence/test_test_scheduler.cpp:117: PASSED:
  CHECK( test_clock::time_point{0ms} == __clock.now() )
with expansion:
  0ms == 0ms

/home/coder/stdexec/test/exec/sequence/test_test_scheduler.cpp:123: PASSED:
  CHECK( test_clock::time_point{1000ms} == __clock.now() )
with expansion:
  1000ms == 1000ms

/home/coder/stdexec/test/exec/sequence/test_test_scheduler.cpp:125: PASSED:
  CHECK( expected == actual )
with expansion:
  { sequence_connect()@0ms, sequence_start()@0ms, set_value('5')@1ms,
  sequence_stopped()@1000ms }
  ==
  { sequence_connect()@0ms, sequence_start()@0ms, set_value('5')@1ms,
  sequence_stopped()@1000ms }
with message:
  __sequence.__marbles_ := { set_value('0')@1ms }

Marbles:

marble_t<_Clock> represents a signal for a sequence
sender and the frame at which the signal occurs/occured

a marble diagram is a string that is parsed into a
vector<marble_t<_Clock>>

Example:
this marble diagram
"--a--b--c|"
is equivalent to this set of marble_t

    marble_t{2ms, ex::set_value, 'a'},
    marble_t{5ms, ex::set_value, 'b'},
    marble_t{8ms, ex::set_value, 'c'},
    marble_t{8ms, sequence_end}

which is displayed as

    set_value('a')@2ms, set_value('b')@5ms,
    set_value('c')@8ms, sequence_end()@8ms

Diagram reference:
Time:

  ' ' indicates that 0ms has elapsed - used to line up diagrams in a visually pleasing manner
  '-' indicates that 1ms has elapsed
  ' 0-9+(ms|s|m) '
      indicates elapsed time at that point in the diagram that is equal to the specified number
      of ms - milliseconds,  s - seconds, m - minutes
      NOTE: must have a preceding and following space to disambiguate from values
  '(' begins a group of signals that all occur on the frame that the group begins on
  ')' ends a group of signals that all occur on the frame that the group begins on

Value:

  '0'-'9' 'a'-'z' 'A'-'Z'
      indicates that a value in the sequence completes with set_value( char )
  '#' indicates that a value in the sequence completes with set_error(error_code(interrupted))
  '.' indicates that a value in the sequence completes with set_stopped()

Sequence:

  '=' indicates connect() on the sequence sender
  '^' indicates start() on the sequence operation
  '|' indicates that the sequence completes with set_value()
  '$' indicates that the sequence completes with set_stopped()
  '?' indicates that request_stop() was sent to the sequence from an external source

record_marbles() will record a set of marbles from the signals of the specified sequence sender

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants