Livt packages
Eccelerators.Cli
Version 1.4.1
Transport-independent, bounded command-line input, parsing, editing, and output for Livt FPGA applications.
Published files (23)
tests/CommandDispatcherTest.lvt
namespace Eccelerators.Cli.Tests
using Eccelerators.Cli
/**
* Checks constructor registration, priority, retries and caller-owned fallback
* directly through CLI bytes, without UART timing or application command code.
*/
@Test
@Context(ClockFrequency = 100MHz)
component CommandDispatcherTest
{
// Owned fixture; only the test process drives the shared CLI.
cli: Cli
first: CommandProbe
second: CommandProbe
fallback: CommandFallback
firstRegistration: CommandRegistration
secondRegistration: CommandRegistration
dispatcher: CommandDispatcher
emptyDispatcher: CommandDispatcher
new()
{
this.cli = new Cli(echoEnabled = false)
this.first = new CommandProbe(this.cli)
this.second = new CommandProbe(this.cli)
this.fallback = new CommandFallback(this.cli)
this.secondRegistration = new CommandRegistration(this.second, this.fallback)
this.firstRegistration = new CommandRegistration(this.first, this.secondRegistration)
this.dispatcher = new CommandDispatcher(this.cli, this.firstRegistration)
this.emptyDispatcher = new CommandDispatcher(this.cli, this.fallback)
}
fn Expect(expected: byte[])
{
for (var index = 0; index < expected.Length; index++) {
assert this.cli.HasOutput()
assert this.cli.PeekOutput() == expected[index]
assert this.cli.ConsumeOutput()
}
assert !this.cli.HasOutput()
}
fn StartSession()
{
this.cli.Reset()
this.first.attempts = 0
this.second.attempts = 0
this.fallback.attempts = 0
assert this.cli.Service()
this.Expect("> ".Encode())
}
fn QueueCommand(line: byte[])
{
for (var index = 0; index < line.Length; index++) {
assert this.cli.AcceptByte(line[index])
}
assert this.cli.HasCommand()
}
fn FillOutput()
{
for (var index = 0; index < 64; index++) {
assert this.cli.TryWriteByte(0x78)
}
}
fn DrainOutput()
{
assert this.cli.GetOutputCount() == 64
for (var index = 0; index < 64; index++) {
assert this.cli.PeekOutput() == 0x78
assert this.cli.ConsumeOutput()
}
}
@Test
fn FirstMatchCompletesOnceAndIdleDispatchDoesNothing()
{
this.StartSession()
this.dispatcher.Dispatch()
assert this.first.attempts == 0
assert this.fallback.attempts == 0
this.QueueCommand("ping\n".Encode())
this.dispatcher.Dispatch()
assert !this.cli.HasCommand()
this.Expect("Pong\r\n".Encode())
assert this.first.attempts == 1
assert this.second.attempts == 0
assert this.fallback.attempts == 0
assert this.cli.Service()
this.Expect("> ".Encode())
this.dispatcher.Dispatch()
assert this.first.attempts == 1
assert !this.cli.HasOutput()
}
@Test
fn BlockedMatchRetriesWithoutFallingThrough()
{
this.StartSession()
this.QueueCommand("ping\n".Encode())
this.FillOutput()
this.dispatcher.Dispatch()
this.dispatcher.Dispatch()
assert this.cli.HasCommand()
assert this.first.attempts == 2
assert this.second.attempts == 0
assert this.fallback.attempts == 0
this.DrainOutput()
this.dispatcher.Dispatch()
assert !this.cli.HasCommand()
assert this.first.attempts == 3
this.Expect("Pong\r\n".Encode())
}
@Test
fn CustomFallbackRetriesAndAlsoServesAnEmptyRegistry()
{
this.StartSession()
this.QueueCommand("other\n".Encode())
this.FillOutput()
this.dispatcher.Dispatch()
assert this.cli.HasCommand()
assert this.first.attempts == 0
assert this.second.attempts == 0
assert this.fallback.attempts == 1
this.DrainOutput()
this.dispatcher.Dispatch()
assert !this.cli.HasCommand()
assert this.fallback.attempts == 2
this.Expect("No handler\r\n".Encode())
this.StartSession()
this.QueueCommand("ping\n".Encode())
this.emptyDispatcher.Dispatch()
assert !this.cli.HasCommand()
assert this.first.attempts == 0
assert this.second.attempts == 0
assert this.fallback.attempts == 1
this.Expect("No handler\r\n".Encode())
}
}