Add schema-6 profiles, atomic catalog migration, shortcuts, Shift, configurable Turbo/Burst, macro recording and playback. Promote qualified 300 MHz native DualSense transport to AIO/XInput defaults with bounded bus transactions, credit batching and generation-safe persistent rumble.
522 lines
22 KiB
C++
522 lines
22 KiB
C++
#include "input/controller_macro_capture.h"
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
|
|
namespace {
|
|
|
|
void require(bool condition, const char* message) {
|
|
if (!condition) {
|
|
std::cerr << message << '\n';
|
|
std::exit(1);
|
|
}
|
|
}
|
|
|
|
CaptureEvent captured_event(const ControllerMacroCapture& capture,
|
|
uint16_t index) {
|
|
CaptureEvent event{};
|
|
require(capture.event(index, &event), "recorded event was inaccessible");
|
|
return event;
|
|
}
|
|
|
|
void require_terminal_frozen(ControllerMacroCapture& capture,
|
|
CaptureState expected, uint32_t elapsed) {
|
|
const uint16_t count = capture.event_count();
|
|
capture.stop(90000000);
|
|
capture.disconnect(capture.slot(), capture.generation(), 90000001);
|
|
capture.observe(capture.slot(), capture.generation(), 90000002,
|
|
controller_neutral_state());
|
|
capture.tick(90000003);
|
|
require(capture.state() == expected &&
|
|
capture.elapsed_us(90000004) == elapsed &&
|
|
capture.event_count() == count,
|
|
"a terminal capture changed state, end time or event count");
|
|
}
|
|
|
|
void test_initial_snapshot_and_start_validation() {
|
|
ControllerMacroCapture capture;
|
|
CaptureEvent output{};
|
|
require(capture.state() == CaptureState::kIdle &&
|
|
capture.elapsed_us(1234) == 0 &&
|
|
!capture.event(0, &output),
|
|
"idle capture exposed an event or running clock");
|
|
capture.stop(10);
|
|
capture.disconnect(0, 0, 11);
|
|
capture.tick(12);
|
|
require(capture.state() == CaptureState::kIdle,
|
|
"an operation without a run changed idle state");
|
|
|
|
CaptureOptions options;
|
|
options.channels = 31;
|
|
ControllerState initial = controller_neutral_state();
|
|
initial.button_south = true;
|
|
initial.button_left_stick = true;
|
|
initial.dpad_up = true;
|
|
initial.left_stick_x = -768;
|
|
initial.right_stick_y = 768;
|
|
initial.left_trigger = 1536;
|
|
initial.right_trigger = UINT16_MAX;
|
|
require(capture.start(3, 77, options, 100, initial),
|
|
"valid capture did not start");
|
|
const uint32_t run = capture.run_id();
|
|
const CaptureEvent first = captured_event(capture, 0);
|
|
require(run != 0 && capture.slot() == 3 && capture.generation() == 77 &&
|
|
capture.event_count() == 1 && first.at_us == 0 &&
|
|
first.buttons == ((1u << 0) | (1u << 10) | (1u << 12)) &&
|
|
first.left_x == -1024 && first.right_y == 1024 &&
|
|
first.left_trigger == 2048 && first.right_trigger == UINT16_MAX,
|
|
"capture did not retain the quantized initial state at time zero");
|
|
require(!capture.start(0, 1, options, 200, controller_neutral_state()) &&
|
|
capture.run_id() == run && capture.elapsed_us(180) == 80 &&
|
|
captured_event(capture, 0).buttons == first.buttons,
|
|
"start replaced an active capture");
|
|
require(!capture.event(1, &output) && !capture.event(0, nullptr),
|
|
"event accessor accepted an absent event or null output");
|
|
capture.stop(180);
|
|
|
|
const CaptureOptions invalid[] = {
|
|
{0, 512, 1024, 8, 10000},
|
|
{32, 512, 1024, 8, 10000},
|
|
{1, 0, 1024, 8, 10000},
|
|
{1, 32768, 1024, 8, 10000},
|
|
{1, 512, 0, 8, 10000},
|
|
{1, 512, 1024, 0, 10000},
|
|
{1, 512, 1024, 129, 10000},
|
|
{1, 512, 1024, 8, 0},
|
|
{1, 512, 1024, 8, 80001},
|
|
};
|
|
for (const CaptureOptions& bad : invalid) {
|
|
require(!capture.start(0, 1, bad, 200, initial),
|
|
"invalid capture options were accepted");
|
|
}
|
|
require(!capture.start(4, 1, options, 200, initial) &&
|
|
capture.run_id() == run &&
|
|
capture.state() == CaptureState::kStopped &&
|
|
capture.elapsed_us(200) == 80 &&
|
|
captured_event(capture, 0).buttons == first.buttons,
|
|
"rejected starts damaged the stopped recording");
|
|
|
|
options.axis_quantum = INT16_MAX;
|
|
options.trigger_quantum = UINT16_MAX;
|
|
options.max_events = 128;
|
|
options.max_duration_ms = 80000;
|
|
require(capture.start(0, 1, options, 300, controller_neutral_state()) &&
|
|
capture.run_id() == run + 1 && capture.event_count() == 1 &&
|
|
captured_event(capture, 0).buttons == 0 &&
|
|
capture.elapsed_us(300) == 0,
|
|
"a successful restart did not replace the old run at valid bounds");
|
|
}
|
|
|
|
void test_positional_logical_buttons() {
|
|
constexpr bool ControllerState::* buttons[] = {
|
|
&ControllerState::button_south,
|
|
&ControllerState::button_east,
|
|
&ControllerState::button_west,
|
|
&ControllerState::button_north,
|
|
&ControllerState::button_left_shoulder,
|
|
&ControllerState::button_right_shoulder,
|
|
&ControllerState::button_select,
|
|
&ControllerState::button_start,
|
|
&ControllerState::button_system,
|
|
&ControllerState::button_capture,
|
|
&ControllerState::button_left_stick,
|
|
&ControllerState::button_right_stick,
|
|
&ControllerState::dpad_up,
|
|
&ControllerState::dpad_down,
|
|
&ControllerState::dpad_left,
|
|
&ControllerState::dpad_right,
|
|
};
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.max_events = 17;
|
|
require(capture.start(0, 1, options, 0, controller_neutral_state()),
|
|
"button capture did not start");
|
|
for (uint16_t i = 0; i < 16; ++i) {
|
|
ControllerState state = controller_neutral_state();
|
|
state.*buttons[i] = true;
|
|
capture.observe(0, 1, i + 1, state);
|
|
const CaptureEvent event = captured_event(capture, i + 1);
|
|
require(event.buttons == (1u << i) && event.at_us == i + 1u,
|
|
"a positional button mapped to the wrong logical bit");
|
|
}
|
|
}
|
|
|
|
ControllerState channel_state(uint8_t channels) {
|
|
ControllerState state = controller_neutral_state();
|
|
state.button_south = (channels & 1u) != 0;
|
|
if ((channels & 2u) != 0) {
|
|
state.left_stick_x = 1279;
|
|
state.left_stick_y = -1279;
|
|
}
|
|
if ((channels & 4u) != 0) {
|
|
state.right_stick_x = -1791;
|
|
state.right_stick_y = 1791;
|
|
}
|
|
if ((channels & 8u) != 0) {
|
|
state.left_trigger = 2047;
|
|
}
|
|
if ((channels & 16u) != 0) {
|
|
state.right_trigger = 3071;
|
|
}
|
|
state.motion_sample_count = 1;
|
|
state.motion_samples[0].gyro_x = 1000;
|
|
return state;
|
|
}
|
|
|
|
void test_selected_channels_ignore_unrelated_changes() {
|
|
for (uint8_t channel = 1; channel <= 16; channel <<= 1) {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.channels = channel;
|
|
require(capture.start(0, 1, options, 10, controller_neutral_state()),
|
|
"single-channel capture did not start");
|
|
capture.observe(0, 1, 20, channel_state(31u ^ channel));
|
|
require(capture.event_count() == 1,
|
|
"unselected channels or motion produced a capture edge");
|
|
capture.observe(0, 1, 30, channel_state(31));
|
|
require(capture.event_count() == 2,
|
|
"selected channel did not produce exactly one edge");
|
|
const CaptureEvent event = captured_event(capture, 1);
|
|
require(event.at_us == 20 &&
|
|
event.buttons == (channel == 1 ? 1 : 0) &&
|
|
event.left_x == (channel == 2 ? 1024 : 0) &&
|
|
event.left_y == (channel == 2 ? -1024 : 0) &&
|
|
event.right_x == (channel == 4 ? -1536 : 0) &&
|
|
event.right_y == (channel == 4 ? 1536 : 0) &&
|
|
event.left_trigger == (channel == 8 ? 2048 : 0) &&
|
|
event.right_trigger == (channel == 16 ? 3072 : 0),
|
|
"selected output leaked or omitted a channel");
|
|
}
|
|
}
|
|
|
|
void test_analog_quantization_symmetry_and_endpoints() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.channels = 30;
|
|
ControllerState state = controller_neutral_state();
|
|
state.left_stick_x = 255;
|
|
state.left_stick_y = -255;
|
|
state.left_trigger = 511;
|
|
state.right_trigger = 511;
|
|
require(capture.start(0, 1, options, 100, state),
|
|
"analog capture did not start");
|
|
CaptureEvent event = captured_event(capture, 0);
|
|
require(event.left_x == 0 && event.left_y == 0 &&
|
|
event.left_trigger == 0 && event.right_trigger == 0,
|
|
"near-zero inputs did not quantize to rest");
|
|
|
|
state.left_stick_x = 256;
|
|
state.left_stick_y = -256;
|
|
state.right_stick_x = -768;
|
|
state.right_stick_y = 768;
|
|
state.left_trigger = 512;
|
|
state.right_trigger = 1536;
|
|
capture.observe(0, 1, 101, state);
|
|
event = captured_event(capture, 1);
|
|
require(event.left_x == 512 && event.left_y == -512 &&
|
|
event.right_x == -1024 && event.right_y == 1024 &&
|
|
event.left_trigger == 1024 && event.right_trigger == 2048,
|
|
"half-quantum ties did not round symmetrically away from zero");
|
|
state.left_stick_x = 767;
|
|
state.left_stick_y = -767;
|
|
state.right_stick_x = -1279;
|
|
state.right_stick_y = 1279;
|
|
state.left_trigger = 1535;
|
|
state.right_trigger = 2559;
|
|
capture.observe(0, 1, 102, state);
|
|
require(capture.event_count() == 2,
|
|
"jitter within a quantized bucket produced another edge");
|
|
|
|
state.left_stick_x = INT16_MIN;
|
|
state.left_stick_y = INT16_MAX;
|
|
state.right_stick_x = -INT16_MAX;
|
|
state.right_stick_y = INT16_MAX - 1;
|
|
state.left_trigger = 0;
|
|
state.right_trigger = UINT16_MAX;
|
|
capture.observe(0, 1, 103, state);
|
|
event = captured_event(capture, 2);
|
|
require(event.left_x == INT16_MIN && event.left_y == INT16_MAX &&
|
|
event.right_x == -INT16_MAX && event.right_y == INT16_MAX &&
|
|
event.left_trigger == 0 && event.right_trigger == UINT16_MAX,
|
|
"quantization wrapped, lost full scale or broke signed symmetry");
|
|
capture.observe(0, 1, 104, controller_neutral_state());
|
|
event = captured_event(capture, 3);
|
|
require(event.left_x == 0 && event.left_y == 0 && event.right_x == 0 &&
|
|
event.right_y == 0 && event.left_trigger == 0 &&
|
|
event.right_trigger == 0,
|
|
"returning to exact rest retained a quantized analog value");
|
|
capture.stop(105);
|
|
|
|
options.axis_quantum = 3;
|
|
options.trigger_quantum = 3;
|
|
state.left_stick_x = 1;
|
|
state.left_stick_y = -1;
|
|
state.right_stick_x = 2;
|
|
state.right_stick_y = -2;
|
|
state.left_trigger = 1;
|
|
state.right_trigger = 2;
|
|
require(capture.start(0, 2, options, 200, state),
|
|
"odd-quantum capture did not start");
|
|
event = captured_event(capture, 0);
|
|
require(event.left_x == 0 && event.left_y == 0 && event.right_x == 3 &&
|
|
event.right_y == -3 && event.left_trigger == 0 &&
|
|
event.right_trigger == 3,
|
|
"odd quanta shifted the signed or unsigned rounding threshold");
|
|
}
|
|
|
|
void test_same_timestamp_coalesces_before_budget_check() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.max_events = 2;
|
|
ControllerState state = controller_neutral_state();
|
|
require(capture.start(0, 1, options, 10, state),
|
|
"coalescing capture did not start");
|
|
state.button_south = true;
|
|
capture.observe(0, 1, 10, state);
|
|
state.button_south = false;
|
|
capture.observe(0, 1, 10, state);
|
|
require(capture.event_count() == 1 &&
|
|
captured_event(capture, 0).buttons == 0,
|
|
"same-time initial changes made zero-length intermediate events");
|
|
state.button_south = true;
|
|
capture.observe(0, 1, 20, state);
|
|
state.button_south = false;
|
|
state.button_west = true;
|
|
capture.observe(0, 1, 20, state);
|
|
capture.observe(0, 1, 21, state);
|
|
require(capture.state() == CaptureState::kRecording &&
|
|
capture.event_count() == 2 &&
|
|
captured_event(capture, 1).buttons == (1u << 2),
|
|
"a full event budget rejected coalescing or an unchanged sample");
|
|
state.button_west = false;
|
|
state.button_north = true;
|
|
capture.observe(0, 1, 22, state);
|
|
require(capture.state() == CaptureState::kFull &&
|
|
capture.elapsed_us(30) == 12 && capture.event_count() == 2 &&
|
|
captured_event(capture, 1).at_us == 10 &&
|
|
captured_event(capture, 1).buttons == (1u << 2),
|
|
"overflow did not retain the last complete recorded state");
|
|
require_terminal_frozen(capture, CaptureState::kFull, 12);
|
|
}
|
|
|
|
void test_full_static_capacity() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.max_events = 128;
|
|
ControllerState state = controller_neutral_state();
|
|
require(capture.start(0, 1, options, 0, state),
|
|
"maximum-capacity capture did not start");
|
|
for (uint16_t i = 1; i < 128; ++i) {
|
|
state.button_south = (i & 1u) != 0;
|
|
capture.observe(0, 1, i, state);
|
|
}
|
|
require(capture.event_count() == 128 &&
|
|
capture.state() == CaptureState::kRecording,
|
|
"capture stopped before an edge exceeded its full capacity");
|
|
state.button_south = false;
|
|
capture.observe(0, 1, 128, state);
|
|
require(capture.state() == CaptureState::kFull &&
|
|
capture.event_count() == 128 && capture.elapsed_us(129) == 128 &&
|
|
captured_event(capture, 127).at_us == 127 &&
|
|
captured_event(capture, 127).buttons == 1,
|
|
"capacity overflow overwrote retained events or lost its end time");
|
|
}
|
|
|
|
void test_clock_wrap_and_stopped_end() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
ControllerState state = controller_neutral_state();
|
|
constexpr uint32_t started = UINT32_MAX - 100u;
|
|
require(capture.start(0, 1, options, started, state),
|
|
"wrap capture did not start");
|
|
state.button_east = true;
|
|
capture.observe(0, 1, 49, state);
|
|
require(captured_event(capture, 1).at_us == 150 &&
|
|
capture.elapsed_us(49) == 150,
|
|
"microsecond clock wrap changed elapsed event timing");
|
|
capture.stop(149);
|
|
require_terminal_frozen(capture, CaptureState::kStopped, 250);
|
|
}
|
|
|
|
void test_long_holds_and_exact_timeout() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.max_duration_ms = 80000;
|
|
ControllerState held = controller_neutral_state();
|
|
held.button_south = true;
|
|
constexpr uint32_t start = 123;
|
|
require(capture.start(0, 1, options, start, held),
|
|
"long-hold capture did not start");
|
|
capture.tick(start + 10000000);
|
|
require(capture.event_count() == 2 &&
|
|
captured_event(capture, 1).at_us == 10000000,
|
|
"a live ten-second hold did not split at its boundary");
|
|
capture.observe(0, 1, start + 15000000, held);
|
|
require(capture.event_count() == 2,
|
|
"unchanged observation added a spurious hold edge");
|
|
capture.tick(start + 35000000);
|
|
require(capture.event_count() == 4,
|
|
"late tick omitted required ten-second hold boundaries");
|
|
capture.tick(start + 90000000);
|
|
require(capture.state() == CaptureState::kTimedOut &&
|
|
capture.event_count() == 8 &&
|
|
capture.elapsed_us(start + 90000000) == 80000000,
|
|
"long hold did not clip at the exact duration and fit eight steps");
|
|
for (uint16_t i = 0; i < 8; ++i) {
|
|
const CaptureEvent event = captured_event(capture, i);
|
|
require(event.at_us == i * 10000000u && event.buttons == 1,
|
|
"hold split changed the captured state or interval length");
|
|
}
|
|
require_terminal_frozen(capture, CaptureState::kTimedOut, 80000000);
|
|
|
|
options.max_duration_ms = 25000;
|
|
require(capture.start(0, 1, options, 0, held),
|
|
"partial-hold timeout capture did not start");
|
|
capture.tick(40000000);
|
|
require(capture.state() == CaptureState::kTimedOut &&
|
|
capture.event_count() == 3 &&
|
|
captured_event(capture, 2).at_us == 20000000 &&
|
|
capture.elapsed_us(40000000) == 25000000,
|
|
"timeout beyond a hold boundary lost the partial final interval");
|
|
|
|
options.max_duration_ms = 10000;
|
|
options.max_events = 1;
|
|
require(capture.start(0, 1, options, 0, held),
|
|
"single-step timeout capture did not start");
|
|
capture.tick(10000000);
|
|
require(capture.state() == CaptureState::kTimedOut &&
|
|
capture.event_count() == 1 &&
|
|
capture.elapsed_us(20000000) == 10000000,
|
|
"an exact-duration hold created a zero-length edge or false full");
|
|
}
|
|
|
|
void test_hold_splits_follow_edges_and_coalesce() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.max_events = 3;
|
|
options.max_duration_ms = 80000;
|
|
ControllerState state = controller_neutral_state();
|
|
state.button_south = true;
|
|
require(capture.start(0, 1, options, 0, state),
|
|
"edge-relative hold capture did not start");
|
|
state.button_south = false;
|
|
state.button_east = true;
|
|
capture.observe(0, 1, 5000000, state);
|
|
capture.tick(15000000);
|
|
state.button_east = false;
|
|
state.button_west = true;
|
|
capture.observe(0, 1, 15000000, state);
|
|
require(capture.state() == CaptureState::kRecording &&
|
|
capture.event_count() == 3 &&
|
|
captured_event(capture, 1).at_us == 5000000 &&
|
|
captured_event(capture, 2).at_us == 15000000 &&
|
|
captured_event(capture, 2).buttons == (1u << 2),
|
|
"hold boundary did not follow or coalesce with a real edge");
|
|
capture.stop(25000000);
|
|
require(capture.state() == CaptureState::kStopped &&
|
|
capture.event_count() == 3 &&
|
|
capture.elapsed_us(30000000) == 25000000,
|
|
"stop at the final hold boundary added an unnecessary event");
|
|
}
|
|
|
|
void test_hold_budget_exhaustion_and_stop_catchup() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.max_events = 2;
|
|
options.max_duration_ms = 80000;
|
|
ControllerState state = controller_neutral_state();
|
|
state.button_south = true;
|
|
require(capture.start(0, 1, options, 0, state),
|
|
"bounded hold capture did not start");
|
|
capture.tick(UINT32_MAX);
|
|
require(capture.state() == CaptureState::kFull &&
|
|
capture.elapsed_us(UINT32_MAX) == 20000000 &&
|
|
capture.event_count() == 2 &&
|
|
captured_event(capture, 1).at_us == 10000000 &&
|
|
captured_event(capture, 1).buttons == 1,
|
|
"large tick did not stop full at the first missing hold boundary");
|
|
require_terminal_frozen(capture, CaptureState::kFull, 20000000);
|
|
|
|
options.max_events = 4;
|
|
require(capture.start(0, 1, options, 0, state),
|
|
"stop-catchup capture did not start");
|
|
capture.stop(35000000);
|
|
require(capture.state() == CaptureState::kStopped &&
|
|
capture.event_count() == 4 &&
|
|
captured_event(capture, 3).at_us == 30000000 &&
|
|
capture.elapsed_us(50000000) == 35000000,
|
|
"stop without intervening ticks omitted long-hold splits");
|
|
}
|
|
|
|
void test_generation_replacement_disconnect_and_slot_isolation() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
ControllerState initial = controller_neutral_state();
|
|
initial.button_south = true;
|
|
ControllerState replacement = controller_neutral_state();
|
|
replacement.button_east = true;
|
|
require(capture.start(2, 7, options, 100, initial),
|
|
"generation capture did not start");
|
|
capture.observe(3, 99, 150, replacement);
|
|
capture.disconnect(3, 7, 170);
|
|
capture.disconnect(2, 6, 180);
|
|
require(capture.state() == CaptureState::kRecording &&
|
|
capture.event_count() == 1,
|
|
"another slot or stale disconnect interrupted capture");
|
|
capture.observe(2, 8, 200, replacement);
|
|
require(capture.state() == CaptureState::kDisconnected &&
|
|
capture.generation() == 7 && capture.event_count() == 1 &&
|
|
captured_event(capture, 0).buttons == 1 &&
|
|
capture.elapsed_us(250) == 100,
|
|
"generation replacement recorded the new device or lost the end");
|
|
require_terminal_frozen(capture, CaptureState::kDisconnected, 100);
|
|
|
|
require(capture.start(2, 8, options, 300, replacement),
|
|
"replacement generation could not start a new capture");
|
|
capture.disconnect(2, 7, 400);
|
|
require(capture.state() == CaptureState::kRecording,
|
|
"old-generation disconnect ended a replacement run");
|
|
capture.disconnect(2, 8, 450);
|
|
require_terminal_frozen(capture, CaptureState::kDisconnected, 150);
|
|
}
|
|
|
|
void test_deadline_precedes_late_edges_and_terminal_requests() {
|
|
ControllerMacroCapture capture;
|
|
CaptureOptions options;
|
|
options.max_duration_ms = 1;
|
|
ControllerState state = controller_neutral_state();
|
|
require(capture.start(0, 1, options, 0, state),
|
|
"deadline capture did not start");
|
|
state.button_south = true;
|
|
capture.observe(0, 1, 1000, state);
|
|
require(capture.state() == CaptureState::kTimedOut &&
|
|
capture.event_count() == 1 &&
|
|
captured_event(capture, 0).buttons == 0 &&
|
|
capture.elapsed_us(2000) == 1000,
|
|
"an edge at the deadline escaped timeout clipping");
|
|
require(capture.start(0, 1, options, 0, state),
|
|
"late-stop capture did not start");
|
|
capture.stop(2000);
|
|
require_terminal_frozen(capture, CaptureState::kTimedOut, 1000);
|
|
require(capture.start(0, 1, options, 0, state),
|
|
"late-disconnect capture did not start");
|
|
capture.disconnect(0, 1, 2000);
|
|
require_terminal_frozen(capture, CaptureState::kTimedOut, 1000);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main() {
|
|
test_initial_snapshot_and_start_validation();
|
|
test_positional_logical_buttons();
|
|
test_selected_channels_ignore_unrelated_changes();
|
|
test_analog_quantization_symmetry_and_endpoints();
|
|
test_same_timestamp_coalesces_before_budget_check();
|
|
test_full_static_capacity();
|
|
test_clock_wrap_and_stopped_end();
|
|
test_long_holds_and_exact_timeout();
|
|
test_hold_splits_follow_edges_and_coalesce();
|
|
test_hold_budget_exhaustion_and_stop_catchup();
|
|
test_generation_replacement_disconnect_and_slot_isolation();
|
|
test_deadline_precedes_late_edges_and_terminal_requests();
|
|
return 0;
|
|
}
|