82 lines
3.5 KiB
Ruby
82 lines
3.5 KiB
Ruby
# encoding: UTF-8
|
|
|
|
require_relative "test_helper"
|
|
require_relative "../lib/meow/gmcp"
|
|
require_relative "../lib/meow/telnet"
|
|
|
|
module MeowGMCPTest
|
|
Telnet = MeowClient::Telnet
|
|
GMCP = MeowClient::GMCP
|
|
|
|
def self.bytes(*values)
|
|
values.pack("C*")
|
|
end
|
|
|
|
def self.frame(payload)
|
|
bytes(Telnet::IAC, Telnet::SB, Telnet::GMCP) + payload.b + bytes(Telnet::IAC, Telnet::SE)
|
|
end
|
|
|
|
MeowTest.test("GMCP negotiation sends DO and emits enabled once") do
|
|
parser = Telnet::Parser.new
|
|
packet = bytes(Telnet::IAC, Telnet::WILL, Telnet::GMCP)
|
|
first = parser.feed(packet)
|
|
duplicate = parser.feed(packet)
|
|
MeowTest.assert_equal([bytes(Telnet::IAC, Telnet::DO, Telnet::GMCP)], first.replies)
|
|
MeowTest.assert_equal([[:gmcp_enabled, true]], first.events)
|
|
MeowTest.assert_empty(duplicate.replies)
|
|
MeowTest.assert_empty(duplicate.events)
|
|
end
|
|
|
|
MeowTest.test("GMCP parses fragmented UTF-8 JSON without entering text output") do
|
|
parser = Telnet::Parser.new
|
|
parser.feed(bytes(Telnet::IAC, Telnet::WILL, Telnet::GMCP))
|
|
packet = frame('Room.Info {"name":"Café","exits":{"n":2}}'.encode("UTF-8"))
|
|
result = {:data => +"".b, :events => []}
|
|
packet.each_byte do |byte|
|
|
parsed = parser.feed(bytes(byte))
|
|
result[:data] << parsed.data
|
|
result[:events].concat(parsed.events)
|
|
end
|
|
message = result[:events][0][1]
|
|
MeowTest.assert_empty(result[:data])
|
|
MeowTest.assert_equal("Room.Info", message.package)
|
|
MeowTest.assert_equal("Café", message.data["name"])
|
|
end
|
|
|
|
MeowTest.test("GMCP reports invalid JSON and continues parsing") do
|
|
parser = Telnet::Parser.new
|
|
parser.feed(bytes(Telnet::IAC, Telnet::WILL, Telnet::GMCP))
|
|
bad = parser.feed(frame("Char.Vitals {bad"))
|
|
good = parser.feed(frame('Char.Vitals {"hp":10}'))
|
|
MeowTest.assert_equal(:gmcp_error, bad.events[0][0])
|
|
MeowTest.assert_equal(10, good.events[0][1].data["hp"])
|
|
end
|
|
|
|
MeowTest.test("GMCP outbound packets JSON encode and escape IAC") do
|
|
packet = Telnet.gmcp_packet("Core.Hello", {"client" => "Meow", "marker" => "\u00ff"})
|
|
MeowTest.assert_equal(bytes(Telnet::IAC, Telnet::SB, Telnet::GMCP), packet.byteslice(0, 3))
|
|
MeowTest.assert_equal(bytes(Telnet::IAC, Telnet::SE), packet.byteslice(-2, 2))
|
|
MeowTest.assert(packet.include?('"client":"Meow"'))
|
|
end
|
|
|
|
MeowTest.test("GMCP state applies incremental room and item updates") do
|
|
state = GMCP::State.new
|
|
state.apply(GMCP::Message.new(:package => "Room.Players", :data => [{"name" => "One"}]))
|
|
state.apply(GMCP::Message.new(:package => "room.addplayer", :data => {"name" => "Two"}))
|
|
state.apply(GMCP::Message.new(:package => "ROOM.REMOVEPLAYER", :data => "One"))
|
|
state.apply(GMCP::Message.new(:package => "Char.Items.List", :data => {"location" => "inv", "items" => [{"id" => 1, "name" => "coin"}]}))
|
|
state.apply(GMCP::Message.new(:package => "Char.Items.Update", :data => {"location" => "inv", "item" => {"id" => 1, "attrib" => "t"}}))
|
|
MeowTest.assert_equal(["Two"], state.room["players"].map { |row| row["name"] })
|
|
MeowTest.assert_equal("coin", state.items["inv"][0]["name"])
|
|
MeowTest.assert_equal("t", state.items["inv"][0]["attrib"])
|
|
end
|
|
|
|
MeowTest.test("GMCP codec enforces payload and nesting bounds") do
|
|
oversized = "Core.Ping " + ("x" * GMCP::MAX_PAYLOAD_BYTES)
|
|
MeowTest.assert_raises(GMCP::ParseError) { GMCP::Codec.parse(oversized) }
|
|
nested = "null"
|
|
(GMCP::MAX_DEPTH + 2).times { nested = "[#{nested}]" }
|
|
MeowTest.assert_raises(GMCP::ParseError) { GMCP::Codec.parse("Test.Value #{nested}") }
|
|
end
|
|
end
|