# encoding: UTF-8 require "zlib" require_relative "test_helper" require_relative "../lib/meow/telnet" require_relative "../lib/meow/text_pipeline" module MeowTextPipelineTest Telnet = MeowClient::Telnet def self.bytes(*values) values.pack("C*") end MeowTest.test("ANSI CSI and OSC sequences are filtered across chunks") do pipeline = MeowClient::TextPipeline.new("UTF-8") records = [] records.concat(pipeline.feed("red\e[3".b).records) records.concat(pipeline.feed("1m text\e]0;title\e".b).records) records.concat(pipeline.feed("\\tail\r\n".b).records) MeowTest.assert_equal(["red texttail"], records) end MeowTest.test("Line framing handles CRLF CR-NUL bare CR and LF across chunks") do pipeline = MeowClient::TextPipeline.new("UTF-8") MeowTest.assert_equal(["one"], pipeline.feed("one\r".b).records) MeowTest.assert_equal(["two"], pipeline.feed("\ntwo\r".b).records) MeowTest.assert_equal(["three"], pipeline.feed("\0three\n".b).records) MeowTest.assert_equal(["four"], pipeline.feed("four\rfive".b).records) MeowTest.assert_equal(["five"], pipeline.finish) end MeowTest.test("UTF-8 characters survive arbitrary byte boundaries") do encoded = "Price: €\n".encode("UTF-8").b pipeline = MeowClient::TextPipeline.new("UTF-8") records = [] encoded.each_byte { |byte| records.concat(pipeline.feed(bytes(byte)).records) } MeowTest.assert_equal(["Price: €"], records) end MeowTest.test("Invalid and incomplete UTF-8 are replaced safely") do pipeline = MeowClient::TextPipeline.new("UTF-8") invalid = pipeline.feed("bad\xC0\n".b) MeowTest.assert_equal(["bad\uFFFD"], invalid.records) incomplete = MeowClient::TextPipeline.new("UTF-8") incomplete.feed("tail \xE2\x82".b) MeowTest.assert_equal(["tail \uFFFD"], incomplete.finish) end MeowTest.test("Legacy encodings are converted to UTF-8") do windows = MeowClient::TextPipeline.new("Windows-1252") latin = MeowClient::TextPipeline.new("ISO-8859-1") MeowTest.assert_equal(["€"], windows.feed("\x80\n".b).records) MeowTest.assert_equal(["é"], latin.feed("\xE9\n".b).records) end MeowTest.test("Prompts can be detected flushed and finished") do pipeline = MeowClient::TextPipeline.new("UTF-8") MeowTest.assert_empty(pipeline.feed("Password: ".b).records) MeowTest.assert(pipeline.prompt_due?(0)) MeowTest.assert_equal("Password: ", pipeline.flush_prompt) MeowTest.refute(pipeline.prompt_due?(0)) pipeline.feed("unfinished".b) MeowTest.assert_equal(["unfinished"], pipeline.finish) end MeowTest.test("Text pipeline propagates Telnet replies and echo state") do pipeline = MeowClient::TextPipeline.new("UTF-8") packet = "hello".b + bytes(Telnet::IAC, Telnet::WILL, Telnet::ECHO) + " world\r\n".b result = pipeline.feed(packet) MeowTest.assert_equal(["hello world"], result.records) MeowTest.assert_equal([bytes(Telnet::IAC, Telnet::DO, Telnet::ECHO)], result.replies) MeowTest.assert_equal([[:remote_echo, true]], result.events) MeowTest.assert(pipeline.remote_echo?) end MeowTest.test("Text pipeline processes MCCP2 output normally") do pipeline = MeowClient::TextPipeline.new("UTF-8") negotiation = bytes(Telnet::IAC, Telnet::WILL, Telnet::COMPRESS2) marker = bytes(Telnet::IAC, Telnet::SB, Telnet::COMPRESS2, Telnet::IAC, Telnet::SE) payload = "red\e[31m text\e[0m\r\n".b result = pipeline.feed(negotiation + marker + Zlib::Deflate.deflate(payload)) MeowTest.assert_equal(["red text"], result.records) MeowTest.assert_equal([bytes(Telnet::IAC, Telnet::DO, Telnet::COMPRESS2)], result.replies) MeowTest.assert_equal([[:compression, true]], result.events) ensure pipeline.close if pipeline != nil end end