Add profile automation and transcripts
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require_relative "test_helper"
|
||||
require_relative "../lib/meow/automation"
|
||||
|
||||
module MeowAutomationTest
|
||||
Automation = MeowClient::Automation
|
||||
|
||||
class FakeProgram
|
||||
def initialize
|
||||
@documents = {}
|
||||
end
|
||||
|
||||
def read_json(name, default:)
|
||||
Marshal.load(Marshal.dump(@documents.fetch(name, default)))
|
||||
end
|
||||
|
||||
def update_json(name, default:)
|
||||
value = Marshal.load(Marshal.dump(@documents.fetch(name, default)))
|
||||
yield value
|
||||
@documents[name] = value
|
||||
end
|
||||
end
|
||||
|
||||
MeowTest.test("Automation templates expand aliases and regular expression captures") do
|
||||
MeowTest.assert_equal("cast fire goblin $", Automation::Template.alias_expand("cast $1 $2 $$", "fire goblin"))
|
||||
match = /(red) (dragon)/.match("red dragon")
|
||||
MeowTest.assert_equal("dragon/red dragon/$", Automation::Template.match_expand("$2/$0/$$", match))
|
||||
end
|
||||
|
||||
MeowTest.test("Automation repository round trips normalized profile rules") do
|
||||
repository = Automation::Repository.new(FakeProgram.new)
|
||||
configuration = repository.default_configuration
|
||||
configuration["aliases"] << {"name" => "Heal", "key" => "h", "command" => "cast heal $*", "enabled" => true}
|
||||
configuration["shortcuts"] << {"name" => "Look", "digit" => 1, "shift" => false, "command" => "look", "enabled" => true}
|
||||
saved = repository.save("profile", configuration)
|
||||
loaded = repository.load("profile")
|
||||
MeowTest.assert_equal(saved, loaded)
|
||||
MeowTest.assert(saved["aliases"][0]["id"].to_s != "")
|
||||
end
|
||||
|
||||
MeowTest.test("Automation repository rejects duplicate aliases and shortcuts") do
|
||||
repository = Automation::Repository.new(FakeProgram.new)
|
||||
configuration = repository.default_configuration
|
||||
configuration["aliases"] = [
|
||||
{"name" => "One", "key" => "x", "command" => "one"},
|
||||
{"name" => "Two", "key" => "X", "command" => "two"}
|
||||
]
|
||||
MeowTest.assert_raises(ArgumentError) { repository.save("profile", configuration) }
|
||||
|
||||
configuration = repository.default_configuration
|
||||
configuration["shortcuts"] = [
|
||||
{"name" => "One", "digit" => 1, "shift" => false, "command" => "one"},
|
||||
{"name" => "Two", "digit" => 1, "shift" => false, "command" => "two"}
|
||||
]
|
||||
MeowTest.assert_raises(ArgumentError) { repository.save("profile", configuration) }
|
||||
end
|
||||
|
||||
MeowTest.test("Command processor expands only one exact first-word alias") do
|
||||
processor = Automation::CommandProcessor.new([
|
||||
{"key" => "k", "command" => "kill $1", "enabled" => true},
|
||||
{"key" => "disabled", "command" => "say no", "enabled" => false}
|
||||
])
|
||||
MeowTest.assert_equal("kill orc", processor.process("K orc"))
|
||||
MeowTest.assert_equal("kk orc", processor.process("kk orc"))
|
||||
MeowTest.assert_equal("k orc", processor.process("k orc", :expand_aliases => false))
|
||||
end
|
||||
|
||||
MeowTest.test("Output processor applies ordered actions against original input") do
|
||||
spoken = []
|
||||
sent = []
|
||||
media = []
|
||||
triggers = [
|
||||
{
|
||||
"enabled" => true,
|
||||
"pattern" => "HP: (\\d+)",
|
||||
"case_sensitive" => false,
|
||||
"actions" => [
|
||||
{"type" => "rewrite", "text" => "Health $1"},
|
||||
{"type" => "highlight", "label" => "Warning", "source" => "tone.wav"},
|
||||
{"type" => "speak", "text" => "Health is $1"},
|
||||
{"type" => "send", "text" => "score"}
|
||||
]
|
||||
}
|
||||
]
|
||||
processor = Automation::OutputProcessor.new(
|
||||
triggers,
|
||||
{
|
||||
:speak => proc { |text| spoken << text },
|
||||
:send => proc { |text| sent << text },
|
||||
:play_media => proc { |source, _action| media << source }
|
||||
}
|
||||
)
|
||||
result = processor.process("hp: 12")
|
||||
MeowTest.assert_equal("Warning: Health 12", result.text)
|
||||
MeowTest.refute(result.gagged)
|
||||
MeowTest.assert_equal(["Health is 12"], spoken)
|
||||
MeowTest.assert_equal(["score"], sent)
|
||||
MeowTest.assert_equal(["tone.wav"], media)
|
||||
end
|
||||
|
||||
MeowTest.test("Gag suppresses output while preserving side effects") do
|
||||
spoken = []
|
||||
processor = Automation::OutputProcessor.new(
|
||||
[{"enabled" => true, "pattern" => "secret", "actions" => [{"type" => "gag"}, {"type" => "speak", "text" => "noticed"}]}],
|
||||
{:speak => proc { |text| spoken << text }}
|
||||
)
|
||||
result = processor.process("secret")
|
||||
MeowTest.assert(result.gagged)
|
||||
MeowTest.assert_equal(["noticed"], spoken)
|
||||
end
|
||||
|
||||
MeowTest.test("Automation send limiter suspends a runaway rule") do
|
||||
now = 10.0
|
||||
sent = []
|
||||
suspended = 0
|
||||
processor = Automation::OutputProcessor.new(
|
||||
[],
|
||||
{:send => proc { |text| sent << text }, :suspended => proc { suspended += 1 }},
|
||||
:clock => proc { now }
|
||||
)
|
||||
actions = [{"type" => "send", "text" => "look"}]
|
||||
(Automation::MAX_AUTOMATED_SENDS_PER_SECOND + 1).times { processor.execute_actions(actions) }
|
||||
MeowTest.assert_equal(Automation::MAX_AUTOMATED_SENDS_PER_SECOND, sent.size)
|
||||
MeowTest.assert_equal(1, suspended)
|
||||
end
|
||||
|
||||
MeowTest.test("Timer scheduler starts at session time and skips missed bursts") do
|
||||
now = 100.0
|
||||
scheduler = Automation::TimerScheduler.new(
|
||||
[{"name" => "pulse", "enabled" => true, "interval" => 5.0, "actions" => []}],
|
||||
:clock => proc { now }
|
||||
)
|
||||
MeowTest.assert_empty(scheduler.due)
|
||||
now = 105.0
|
||||
MeowTest.assert_equal(["pulse"], scheduler.due.map { |row| row["name"] })
|
||||
now = 130.0
|
||||
MeowTest.assert_equal(["pulse"], scheduler.due.map { |row| row["name"] })
|
||||
MeowTest.assert_empty(scheduler.due)
|
||||
end
|
||||
|
||||
MeowTest.test("Automation media distinguishes Windows files from secure URLs") do
|
||||
MeowTest.assert_equal(:local, Automation::MediaSource.classify("C:\\sounds\\alert.ogg"))
|
||||
MeowTest.assert_equal(:local, Automation::MediaSource.classify("\\\\server\\sounds\\alert.wav"))
|
||||
MeowTest.assert_equal(:https, Automation::MediaSource.classify("https://media.example/alert.mp3"))
|
||||
MeowTest.assert_raises(ArgumentError) { Automation::MediaSource.classify("http://media.example/alert.mp3") }
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user