# encoding: UTF-8 require_relative "test_helper" require_relative "../lib/meow/media" module MeowMediaTest Media = MeowClient::Media class FakeDownloader attr_reader :results, :requests def initialize @results = Queue.new @requests = [] end def enqueue(id, uri, allow_insecure_http: false) @requests << [id, uri, allow_insecure_http] true end def close end end class FakeHandle attr_accessor :position_ms attr_reader :closed, :restarts, :fade def initialize @position_ms = 0 @closed = false @finished = false @restarts = [] end def finished? @finished end def finish! @finished = true end def restart(position) @finished = false @restarts << position end def stop(fade = 0) @fade = fade @closed = true end def close @closed = true end end class FakeBackend attr_reader :starts def initialize @starts = [] end def start(path, request, volume) handle = FakeHandle.new @starts << [path, request, volume, handle] handle end end MeowTest.test("Media URL policy accepts safe relative HTTPS audio") do uri = Media::URLPolicy.new.resolve("https://media.example/game/", "weather/rain.ogg") MeowTest.assert_equal("https://media.example/game/weather/rain.ogg", uri.to_s) end MeowTest.test("Media URL policy isolates legacy HTTP from secure requests") do policy = Media::URLPolicy.new MeowTest.assert_raises(ArgumentError) { policy.resolve("http://example.com/", "sound.mp3") } legacy = policy.resolve("http://example.com/", "sound.mp3", nil, :allow_insecure_http => true) MeowTest.assert_equal("http://example.com/sound.mp3", legacy.to_s) MeowTest.assert_raises(ArgumentError) do policy.resolve("http://127.0.0.1/", "sound.mp3", nil, :allow_insecure_http => true) end MeowTest.assert_raises(ArgumentError) { policy.resolve("https://example.com/", "../secret.mp3") } end MeowTest.test("Media manager carries HTTP permission on each request") do downloader = FakeDownloader.new manager = Media::Manager.new("unused", :downloader => downloader) secure = Media::PlayRequest.new(:name => "secure.mp3", :url => "https://media.example/") legacy = Media::PlayRequest.new( :name => "legacy.mid", :url => "http://media.example/", :allow_insecure_http => true ) manager.play(secure) manager.play(legacy) MeowTest.assert_equal(false, downloader.requests[0][2]) MeowTest.assert_equal(true, downloader.requests[1][2]) ensure manager.close if manager != nil end MeowTest.test("Client.Media adapter normalizes play and stop commands") do play = Media::ClientMedia.play_request({"name" => "rain.ogg", "type" => "music", "loops" => -1, "caption" => "Rain"}) stop = Media::ClientMedia.stop_request({"type" => "music", "fadeaway" => true}) MeowTest.assert_equal("rain.ogg", play.name) MeowTest.assert_equal(-1, play.loops) MeowTest.assert(stop.fade_away) end MeowTest.test("Media stop cancels queued playback before its download completes") do downloader = FakeDownloader.new backend = FakeBackend.new manager = Media::Manager.new("unused", :downloader => downloader, :backend => backend) manager.default_url = "https://media.example/game/" request = Media::PlayRequest.new(:name => "late.mp3", :kind => "sound", :key => "door") id = manager.play(request) MeowTest.assert_equal(1, manager.stop(Media::StopRequest.new(:key => "door"))) downloader.results << Media::DownloadResult.new(:id => id, :path => "cached.mp3", :url => "https://media.example/game/late.mp3") manager.tick MeowTest.assert_empty(backend.starts) ensure manager.close if manager != nil end MeowTest.test("Media priority prevents lower-priority playback") do downloader = FakeDownloader.new backend = FakeBackend.new manager = Media::Manager.new("unused", :downloader => downloader, :backend => backend) manager.default_url = "https://media.example/game/" high = Media::PlayRequest.new(:name => "high.mp3", :kind => "sound", :priority => 80) high_id = manager.play(high) downloader.results << Media::DownloadResult.new(:id => high_id, :path => "high.mp3", :url => "https://media.example/game/high.mp3") manager.tick low = Media::PlayRequest.new(:name => "low.mp3", :kind => "sound", :priority => 20) low_id = manager.play(low) downloader.results << Media::DownloadResult.new(:id => low_id, :path => "low.mp3", :url => "https://media.example/game/low.mp3") manager.tick MeowTest.assert_equal(1, backend.starts.size) MeowTest.assert_equal("high.mp3", backend.starts[0][0]) ensure manager.close if manager != nil end MeowTest.test("Media manager downloads starts loops and selectively stops") do downloader = FakeDownloader.new backend = FakeBackend.new manager = Media::Manager.new("unused", :downloader => downloader, :backend => backend, :music_volume => 0.5) manager.default_url = "https://media.example/game/" request = Media::PlayRequest.new(:name => "theme.mp3", :kind => "music", :loops => 2, :volume => 80, :caption => "Theme") id = manager.play(request) downloader.results << Media::DownloadResult.new(:id => id, :path => "cached.mp3", :url => "https://media.example/game/theme.mp3") manager.tick MeowTest.assert_equal(1, manager.tracks.size) MeowTest.assert_equal(0.5, backend.starts[0][2]) MeowTest.assert_equal(["Theme"], manager.captions) MeowTest.assert_equal(["Theme"], manager.drain_captions) MeowTest.assert_empty(manager.drain_captions) handle = backend.starts[0][3] handle.finish! manager.tick MeowTest.assert_equal([0], handle.restarts) manager.stop(Media::StopRequest.new(:kind => "music", :fade_away => true)) MeowTest.assert(handle.closed) MeowTest.assert_equal(5_000, handle.fade) ensure manager.close if manager != nil end end