[DRE-commits] [ruby-notiffany] 08/10: support spec test

Daisuke Higuchi dai at moszumanska.debian.org
Wed Nov 15 15:48:49 UTC 2017


This is an automated email from the git hooks/post-receive script.

dai pushed a commit to branch master
in repository ruby-notiffany.

commit 56b4d084022d7a8436f3343a1cbb59b312702575
Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
Date:   Thu Nov 16 00:43:53 2017 +0900

    support spec test
---
 debian/control                                     |    3 +-
 debian/patches/add-specs.patch                     | 2650 ++++++++++++++++++++
 ...-uninitialized-constant-notiffany-version.patch |   15 +
 debian/patches/series                              |    3 +
 debian/ruby-tests.rake                             |    5 +
 5 files changed, 2675 insertions(+), 1 deletion(-)

diff --git a/debian/control b/debian/control
index cae4048..720b79d 100644
--- a/debian/control
+++ b/debian/control
@@ -6,7 +6,8 @@ Uploaders: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
 Build-Depends: debhelper (>= 10~),
                gem2deb,
                ruby-nenv (>= 0.1),
-               ruby-shellany
+               ruby-shellany,
+               ruby-rspec
 Standards-Version: 4.1.1
 Vcs-Git: https://anonscm.debian.org/git/pkg-ruby-extras/ruby-notiffany.git
 Vcs-Browser: https://anonscm.debian.org/cgit/pkg-ruby-extras/ruby-notiffany.git
diff --git a/debian/patches/add-specs.patch b/debian/patches/add-specs.patch
new file mode 100644
index 0000000..c2d1008
--- /dev/null
+++ b/debian/patches/add-specs.patch
@@ -0,0 +1,2650 @@
+Description: add specs
+Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
+Origin: upstream
+Forwarded: not-needed
+Last-Update: 2017-11-16
+
+Index: ruby-notiffany/Rakefile
+===================================================================
+--- /dev/null
++++ ruby-notiffany/Rakefile
+@@ -0,0 +1,12 @@
++require "bundler/gem_tasks"
++
++require 'nenv'
++
++default_tasks = []
++
++require 'rspec/core/rake_task'
++default_tasks << RSpec::Core::RakeTask.new(:spec) do |t|
++  t.verbose = Nenv.ci?
++end
++
++task default: default_tasks.map(&:name)
+Index: ruby-notiffany/notiffany.gemspec
+===================================================================
+--- ruby-notiffany.orig/notiffany.gemspec
++++ ruby-notiffany/notiffany.gemspec
+@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
+   s.date = "2016-07-29"
+   s.description = "    Wrapper libray for most popular notification\n    libraries such as Growl, Libnotify, Notifu\n".freeze
+   s.email = ["cezary at chronomantic.net".freeze]
+-  s.files = ["LICENSE.txt".freeze, "README.md".freeze, "images/failed.png".freeze, "images/pending.png".freeze, "images/success.png".freeze, "lib/notiffany.rb".freeze, "lib/notiffany/notifier.rb".freeze, "lib/notiffany/notifier/base.rb".freeze, "lib/notiffany/notifier/config.rb".freeze, "lib/notiffany/notifier/detected.rb".freeze, "lib/notiffany/notifier/emacs.rb".freeze, "lib/notiffany/notifier/emacs/client.rb".freeze, "lib/notiffany/notifier/file.rb".freeze, "lib/notiffany/notifier/gn [...]
++  s.files = ["LICENSE.txt".freeze, "README.md".freeze, "images/failed.png".freeze, "images/pending.png".freeze, "images/success.png".freeze, "lib/notiffany.rb".freeze, "lib/notiffany/notifier.rb".freeze, "lib/notiffany/notifier/base.rb".freeze, "lib/notiffany/notifier/config.rb".freeze, "lib/notiffany/notifier/detected.rb".freeze, "lib/notiffany/notifier/emacs.rb".freeze, "lib/notiffany/notifier/emacs/client.rb".freeze, "lib/notiffany/notifier/file.rb".freeze, "lib/notiffany/notifier/gn [...]
+   s.homepage = "https://github.com/guard/notiffany".freeze
+   s.licenses = ["MIT".freeze]
+   s.rubygems_version = "2.5.2.1".freeze
+Index: ruby-notiffany/spec/lib/notiffany/notifier/base_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/base_spec.rb
+@@ -0,0 +1,162 @@
++require "notiffany/notifier/base"
++
++# TODO: no point in testing the base class, really
++module Notiffany
++  RSpec.describe Notifier::Base do
++    let(:fake) { double "fake_lib" }
++    let(:options) { {} }
++    let(:os) { "solaris" }
++
++    subject { Notifier::FooBar.new({ fake: fake }.merge(options)) }
++
++    before do
++      allow(Kernel).to receive(:require)
++      allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++    end
++
++    class Notifier
++      class FooBar < Notifier::Base
++        DEFAULTS = { foo: :bar }
++
++        private
++
++        def _supported_hosts
++          %w(freebsd solaris)
++        end
++
++        def _perform_notify(message, options)
++          options[:fake].notify(message, options)
++        end
++
++        def _check_available(_options)
++          true
++        end
++      end
++    end
++
++    describe "#initialize" do
++      context "on unsupported os" do
++        let(:os) { "mswin" }
++        it "fails" do
++          expect { subject }.to raise_error(Notifier::Base::UnsupportedPlatform)
++        end
++      end
++
++      context "on supported os" do
++        let(:os) { "freebsd" }
++
++        context "library loads normally" do
++          it "returns true" do
++            expect(Kernel).to receive(:require).with("foo_bar")
++            expect { subject }.to_not raise_error
++          end
++        end
++
++        context "when library fails to load" do
++          before do
++            allow(Kernel).to receive(:require).with("foo_bar").
++              and_raise LoadError
++          end
++
++          it "fails with error" do
++            expect { subject }.
++              to raise_error(Notifier::Base::RequireFailed)
++          end
++        end
++      end
++    end
++
++    describe "#name" do
++      it 'un-modulizes the class, replaces "xY" with "x_Y" and downcase' do
++        expect(subject.name).to eq "foo_bar"
++      end
++    end
++
++    describe "#title" do
++      it "un-modulize the class" do
++        expect(subject.title).to eq "FooBar"
++      end
++    end
++
++    describe "#notify" do
++      let(:opts) { {} }
++
++      context "with no notify title overrides" do
++        it "supplies default title" do
++          expect(fake).to receive(:notify).
++            with("foo", hash_including(title: "Notiffany"))
++          subject.notify("foo", opts)
++        end
++      end
++
++      context "with notify title override" do
++        let(:opts) { { title: "Hi" } }
++        it "uses given title" do
++          expect(fake).to receive(:notify).
++            with("foo", hash_including(title: "Hi"))
++          subject.notify("foo", opts)
++        end
++      end
++
++      context "with no type overrides" do
++        it "supplies default type" do
++          expect(fake).to receive(:notify).
++            with("foo", hash_including(type: :success))
++          subject.notify("foo", opts)
++        end
++      end
++
++      context "with type given" do
++        let(:opts) { { type: :foo } }
++        it "uses given type" do
++          expect(fake).to receive(:notify).
++            with("foo", hash_including(type: :foo))
++          subject.notify("foo", opts)
++        end
++      end
++
++      context "with no image overrides" do
++        it "supplies default image" do
++          expect(fake).to receive(:notify).
++            with("foo", hash_including(image: /success.png$/))
++          subject.notify("foo", opts)
++        end
++      end
++
++      %w(failed pending success guard).each do |img|
++        context "with #{img.to_sym.inspect} image" do
++          let(:opts) { { image: img.to_sym } }
++          it "converts to image path" do
++            expect(fake).to receive(:notify).
++              with("foo", hash_including(image: /#{img}.png$/))
++            subject.notify("foo", opts)
++          end
++        end
++      end
++
++      context "with a custom image" do
++        let(:opts) { { image: "foo.jpg" } }
++        it "uses given image" do
++          expect(fake).to receive(:notify).
++            with("foo", hash_including(image: "foo.jpg"))
++          subject.notify("foo", opts)
++        end
++      end
++
++      context "with nil image" do
++        let(:opts) { { image: nil } }
++        it "set the notify image to nil" do
++          expect(fake).to receive(:notify).
++            with("foo", hash_including(image: nil))
++          subject.notify("foo", opts)
++        end
++
++        it "uses the default type" do
++          expect(fake).to receive(:notify).
++            with("foo", hash_including(type: :notify))
++          subject.notify("foo", opts)
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/detected_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/detected_spec.rb
+@@ -0,0 +1,171 @@
++require "notiffany/notifier/detected"
++
++module Notiffany
++  class Notifier
++    RSpec.describe YamlEnvStorage do
++      let(:subject) { YamlEnvStorage.new("notiffany_tests_foo") }
++      describe "#notifiers" do
++        context "when set to empty array" do
++          before { subject.notifiers = [] }
++          specify { expect(subject.notifiers).to be_empty }
++        end
++
++        context "when set to nil" do
++          before { subject.notifiers = nil }
++          specify { expect(subject.notifiers).to be_empty }
++        end
++
++        context "when env is empty" do
++          before { ENV['NOTIFFANY_TESTS_FOO_NOTIFIERS'] = nil }
++          specify { expect(subject.notifiers).to be_empty }
++        end
++      end
++    end
++
++    RSpec.describe(Detected, exclude_stubs: [YamlEnvStorage]) do
++      let(:logger) { double("Logger", debug: nil) }
++
++      subject { described_class.new(supported, "notiffany_tests", logger) }
++
++      let(:env) { instance_double(YamlEnvStorage) }
++
++      let(:foo_mod) { double("foo_mod") }
++      let(:bar_mod) { double("bar_mod") }
++      let(:baz_mod) { double("baz_mod") }
++
++      let(:foo_obj) { double("foo_obj") }
++      let(:baz_obj) { double("baz_obj") }
++
++      let(:supported) { [foo: foo_mod, baz: baz_mod] }
++
++      before do
++        allow(YamlEnvStorage).to receive(:new).and_return(env)
++
++        allow(env).to receive(:notifiers) do
++          fail "stub me: notifiers"
++        end
++
++        allow(env).to receive(:notifiers=) do |args|
++          fail "stub me: notifiers=(#{args.inspect})"
++        end
++      end
++
++      describe "#available" do
++        context "with detected notifiers" do
++          let(:available) do
++            [
++              { name: :foo, options: {} },
++              { name: :baz, options: { opt1: 3 } }
++            ]
++          end
++
++          let(:expected) { [foo_obj, baz_obj] }
++
++          before do
++            allow(foo_mod).to receive(:new).and_return(foo_obj)
++            allow(baz_mod).to receive(:new).and_return(baz_obj)
++            allow(env).to receive(:notifiers).and_return(available)
++          end
++
++          it "returns hash with detected notifier options" do
++            expect(subject.available).to eq(expected)
++          end
++        end
++      end
++
++      describe "#add" do
++        before do
++          allow(env).to receive(:notifiers).and_return(notifiers)
++        end
++
++        context "with no detected notifiers" do
++          let(:notifiers) { [] }
++          context "when unknown" do
++            it "does not add the library" do
++              expect(env).to_not receive(:notifiers=)
++              expect { subject.add(:unknown, {}) }.
++                to raise_error(Notifier::Detected::UnknownNotifier)
++            end
++          end
++        end
++
++        context "with manually configured notifiers" do
++          let(:notifiers) { [] }
++
++          context "when not available" do
++            before do
++              allow(foo_mod).to receive(:new).
++                with(foo: :bar).
++                and_raise(Notifier::Base::UnavailableError, "something failed")
++              allow(logger).to receive(:warning)
++            end
++
++            it "does not add the library" do
++              expect(env).to_not receive(:notifiers=)
++              subject.add(:foo, foo: :bar)
++            end
++
++            it "does not raise an error" do
++              expect { subject.add(:foo, foo: :bar) }.to_not raise_error
++            end
++
++            it "shows a warning" do
++              expect(logger).to receive(:warning).
++                with("Notiffany: foo not available (something failed).")
++              subject.add(:foo, foo: :bar)
++            end
++          end
++        end
++      end
++
++      describe "#detect" do
++        context "with some detected notifiers" do
++          before do
++            allow(env).to receive(:notifiers).and_return([])
++
++            allow(foo_mod).to receive(:new).and_return(foo_obj)
++            allow(baz_mod).to receive(:new).
++              and_raise(Notifier::Base::UnavailableError, "some failure")
++          end
++
++          let(:detected) { [{ name: :foo, options: {} }] }
++
++          it "add detected notifiers to available" do
++            expect(env).to receive(:notifiers=) do |args|
++              expect(args).to eq(detected)
++            end
++
++            allow(env).to receive(:notifiers).and_return([], [], detected)
++            subject.detect
++          end
++        end
++
++        context "without any detected notifiers" do
++          before do
++            allow(env).to receive(:notifiers).and_return([])
++
++            allow(foo_mod).to receive(:new).
++              and_raise(Notifier::Base::UnavailableError, "some error")
++            allow(baz_mod).to receive(:new).
++              and_raise(Notifier::Base::UnavailableError, "some error")
++          end
++
++          let(:error) { described_class::NoneAvailableError }
++          let(:msg) { /could not detect any of the supported notification/ }
++          it { expect { subject.detect }.to raise_error(error, msg) }
++        end
++      end
++
++      describe "#reset" do
++        before do
++          allow(env).to receive(:notifiers=)
++        end
++
++        it "resets the detected notifiers" do
++          expect(env).to receive(:notifiers=).with([])
++          subject.reset
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/emacs/client_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/emacs/client_spec.rb
+@@ -0,0 +1,90 @@
++require 'notiffany/notifier/emacs'
++require 'notiffany/notifier/emacs/client'
++
++RSpec.describe Notiffany::Notifier::Emacs::Client do
++  let(:sheller) { Shellany::Sheller }
++
++  let(:default_options) { { client: 'emacsclient', elisp_erb: elisp_erb } }
++  let(:options) { default_options }
++  subject { described_class.new(options) }
++
++  before do
++    allow(sheller).to receive(:run) do |*args|
++      raise "stub me: #{sheller.class}(#{args.map(&:inspect) * ','})"
++    end
++  end
++
++  describe '#initialize' do
++    context 'when constructed without elisp_erb' do
++      let(:elisp_erb) { nil }
++      let(:options) { default_options.merge(elisp_erb: nil) }
++      it 'fails with an error' do
++        expect do
++          subject
++        end.to raise_error(ArgumentError, 'No :elisp_erb option given!')
++      end
++    end
++  end
++
++  describe '#available?' do
++    let(:elisp_erb) { "'<%= 0+1 %>'" }
++
++    before do
++      allow(sheller).to receive(:run).with(
++        { 'ALTERNATE_EDITOR' => 'false' },
++        'emacsclient',
++        '--eval',
++        "'1'"
++      ).and_return(result)
++    end
++
++    context 'with a working client command' do
++      let(:result) { true }
++      it { is_expected.to be_available }
++    end
++
++    context 'when the client commmand does not exist' do
++      let(:result) { nil }
++      it { is_expected.to_not be_available }
++    end
++
++    context 'when the client command fails' do
++      let(:result) { false }
++      it { is_expected.to_not be_available }
++    end
++  end
++
++  # TODO: handle failure emacs failure due to elisp error?
++  describe '#notify' do
++    context 'when constructed with valid elisp Erb' do
++      let(:elisp_erb) do
++        "( print 'color is <%= color %>, bg color is <%= bgcolor %>' )"
++      end
++
++      let(:result) { true }
++
++      it 'evaluates using given colors' do
++        expect(sheller).to receive(:run).with(
++          anything,
++          'emacsclient',
++          '--eval',
++          "( print 'color is Green, bg color is Black' )"
++        ).and_return(result)
++        subject.notify('Green', 'Black')
++      end
++
++      context 'with a message' do
++        let(:elisp_erb) { "( print 'Info: <%= message %>' )" }
++        it 'evaluates using given message' do
++          expect(sheller).to receive(:run).with(
++            anything,
++            'emacsclient',
++            '--eval',
++            "( print 'Info: FooBar' )"
++          ).and_return(result)
++          subject.notify('Green', 'Black', 'FooBar')
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/emacs_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/emacs_spec.rb
+@@ -0,0 +1,149 @@
++require 'notiffany/notifier/emacs'
++
++RSpec.describe Notiffany::Notifier::Emacs do
++  let(:options) { {} }
++
++  subject { described_class.new(options) }
++
++  let(:availability_command_result) { true }
++  let(:availability_checking_client) do
++    instance_double(
++      described_class::Client,
++      available?: availability_command_result
++    )
++  end
++
++  before do
++    allow(described_class::Client).to receive(:new) do |*args|
++      args_info = args.map(&:inspect) * ','
++      raise "stub me: #{described_class::Client}.new(#{args_info})"
++    end
++
++    allow(described_class::Client).to receive(:new)
++      .with(hash_including(elisp_erb: "'1'"))
++      .and_return(availability_checking_client)
++  end
++
++  before do
++    allow(File).to receive(:expand_path) do |*args|
++      raise "stub me: File.expand_path(#{args.map(&:inspect) * ','})"
++    end
++
++    allow(IO).to receive(:read) do |*args|
++      raise "stub me: IO.read(#{args.map(&:inspect) * ','})"
++    end
++  end
++
++  describe '#initialize' do
++    context 'when the client command works' do
++      let(:availability_command_result) { true }
++      it 'works' do
++        subject
++      end
++    end
++
++    context 'when the client command fails' do
++      let(:availability_command_result) { false }
++      it 'fails' do
++        expect { subject }
++          .to raise_error(Notiffany::Notifier::Base::UnavailableError)
++      end
++    end
++  end
++
++  describe '#notify' do
++    let(:notifying_client) { instance_double(described_class::Client) }
++
++    before do
++      allow(notifying_client).to receive(:notify)
++      default_elisp = { elisp_erb: described_class::DEFAULT_ELISP_ERB }
++      allow(described_class::Client).to receive(:new)
++        .with(hash_including(default_elisp))
++        .and_return(notifying_client)
++    end
++
++    describe 'color' do
++      context 'when left default' do
++        context 'without overriding global options' do
++          it 'is set to default' do
++            expect(notifying_client).to receive(:notify)
++              .with('White', 'ForestGreen', anything)
++            subject.notify('any message')
++          end
++        end
++      end
++
++      context 'when set globally' do
++        let(:options) { { success: 'Pink', silent: true } }
++
++        context 'when no overring notification options' do
++          it 'is set to global value' do
++            expect(notifying_client).to receive(:notify)
++              .with('White', 'Pink', anything)
++            subject.notify('any message')
++          end
++        end
++      end
++
++      context 'when set during notification' do
++        describe 'for :success' do
++          let(:notification_options) { { success: 'Orange' } }
++          it 'is set from the notification value' do
++            expect(notifying_client).to receive(:notify)
++              .with('White', 'Orange', anything)
++            subject.notify('any message', notification_options)
++          end
++        end
++
++        describe 'for :pending' do
++          let(:notification_options) { { type: :pending, pending: 'Yellow' } }
++          it 'is set from the notification value' do
++            expect(notifying_client).to receive(:notify)
++              .with('White', 'Yellow', anything)
++            subject.notify('any message', notification_options)
++          end
++        end
++      end
++    end
++
++    context 'with no elisp file' do
++      let(:options) { {} }
++
++      it 'uses default elisp notification code' do
++        expected_elisp_erb = <<EOF
++(set-face-attribute 'mode-line nil
++  :background "<%= bgcolor %>"
++  :foreground "<%= color %>")
++EOF
++        expected = { elisp_erb: expected_elisp_erb }
++
++        expect(described_class::Client).to receive(:new)
++          .with(hash_including(expected))
++          .and_return(notifying_client)
++        subject.notify('any message')
++      end
++    end
++
++    context 'with elisp file' do
++      let(:options) { { elisp_file: '~/.my_elisp_script' } }
++
++      before do
++        allow(File).to receive(:expand_path)
++          .with('~/.my_elisp_script')
++          .and_return('/foo/bar')
++
++        allow(IO).to receive(:read)
++          .with('/foo/bar')
++          .and_return('( print "hello, color is: <%= color %>" )')
++      end
++
++      it 'passes evaluated erb to client' do
++        expected = { elisp_erb: '( print "hello, color is: <%= color %>" )' }
++        expect(described_class::Client).to receive(:new)
++          .with(hash_including(expected))
++          .and_return(notifying_client)
++        subject.notify('any message')
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/file_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/file_spec.rb
+@@ -0,0 +1,74 @@
++require "notiffany/notifier/file"
++
++module Notiffany
++  RSpec.describe Notifier::File do
++    let(:options) { {} }
++    subject { described_class.new(options) }
++
++    describe "#available" do
++      context "with path option" do
++        let(:options) { { path: ".guard_result" } }
++        it "works" do
++          subject
++        end
++      end
++
++      context "with no path option" do
++        it "fails" do
++          expect { subject }.to raise_error(Notifier::Base::UnavailableError)
++        end
++      end
++    end
++
++    describe "#notify" do
++      let(:options) { { path: "/tmp/foo" } }
++      context "with options passed at initialization" do
++        let(:options) { { path: "tmp/guard_result", silent: true } }
++
++        it "uses these options by default" do
++          expect(File).to receive(:write).
++            with("tmp/guard_result", "success\nany title\nany message\n")
++
++          subject.notify("any message", title: "any title")
++        end
++
++        it "overwrites object options with passed options" do
++          expect(File).to receive(:write).
++            with("tmp/guard_result_final", "success\nany title\nany message\n")
++
++          subject.notify("any message",
++                         title: "any title",
++                         path: "tmp/guard_result_final")
++        end
++      end
++
++      it "writes to a file on success" do
++        expect(File).to receive(:write).
++          with("tmp/guard_result", "success\nany title\nany message\n")
++
++        subject.notify("any message",
++                       title: "any title",
++                       path: "tmp/guard_result")
++      end
++
++      it "also writes to a file on failure" do
++        expect(File).to receive(:write).
++          with("tmp/guard_result", "failed\nany title\nany message\n")
++
++        subject.notify("any message",
++                       type: :failed,
++                       title: "any title",
++                       path: "tmp/guard_result")
++      end
++
++      # We don't have a way to return false in .available? when no path is
++      # specified. So, we just don't do anything in .notify if there's no path.
++      it "does not write to a file if no path is specified" do
++        expect(File).to_not receive(:write)
++
++        expect { subject.notify("any message", path: nil) }.
++          to raise_error(Notifier::Base::UnavailableError)
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/gntp_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/gntp_spec.rb
+@@ -0,0 +1,151 @@
++require "notiffany/notifier/gntp"
++
++module Notiffany
++  RSpec.describe Notifier::GNTP do
++    let(:gntp) { double("GNTP").as_null_object }
++
++    let(:options) { {} }
++    let(:os) { "solaris" }
++    subject { described_class.new(options) }
++
++    before do
++      stub_const "GNTP", gntp
++      allow(Kernel).to receive(:require)
++      allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++    end
++
++    describe ".available?" do
++      context "host is not supported" do
++        let(:os) { "foobar" }
++
++        it "fails" do
++          expect { subject }.to raise_error(Notifier::Base::UnsupportedPlatform)
++        end
++      end
++
++      context "host is supported" do
++        let(:os) { "darwin" }
++
++        it "requires ruby_gntp" do
++          expect(Kernel).to receive(:require).with("ruby_gntp")
++          subject
++        end
++      end
++    end
++
++    describe "#client" do
++      before do
++        allow(::GNTP).to receive(:new) { gntp }
++        allow(gntp).to receive(:register)
++      end
++
++      it "creates a new GNTP client and memoize it" do
++        expect(::GNTP).to receive(:new).
++          with("Notiffany", "127.0.0.1", "", 23_053).once { gntp }
++
++        subject.notify("Welcome")
++        subject.notify("Welcome")
++      end
++
++      it "calls #register on the client and memoize it" do
++        expect(::GNTP).to receive(:new).
++          with("Notiffany", "127.0.0.1", "", 23_053).once { gntp }
++
++        expect(gntp).to receive(:register).once
++
++        subject.notify("Welcome")
++        subject.notify("Welcome")
++      end
++    end
++
++    describe "#notify" do
++      before do
++        expect(::GNTP).to receive(:new).and_return(gntp)
++      end
++
++      context "with options passed at initialization" do
++        let(:options) { { title: "Hello", silent: true } }
++
++        it "uses these options by default" do
++          expect(gntp).to receive(:notify).with(
++            hash_including(
++              sticky: false,
++              name:   "success",
++              title:  "Hello",
++              text:   "Welcome",
++              icon:   "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify(
++            "Welcome",
++            type: :success,
++            image: "/tmp/welcome.png"
++          )
++        end
++
++        it "overwrites object options with passed options" do
++          expect(gntp).to receive(:notify).with(
++            hash_including(
++              sticky: false,
++              name:   "success",
++              title:  "Welcome",
++              text:   "Welcome to Guard",
++              icon:   "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify(
++            "Welcome to Guard",
++            type: :success,
++            title: "Welcome",
++            image: "/tmp/welcome.png"
++          )
++        end
++      end
++
++      context "without additional options" do
++        it "shows the notification with the default options" do
++          expect(gntp).to receive(:notify).with(
++            hash_including(
++              sticky: false,
++              name:   "success",
++              title:  "Welcome",
++              text:   "Welcome to Guard",
++              icon:   "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify(
++            "Welcome to Guard",
++            type: :success,
++            title: "Welcome",
++            image: "/tmp/welcome.png"
++          )
++        end
++      end
++
++      context "with additional options" do
++        it "can override the default options" do
++          expect(gntp).to receive(:notify).with(
++            hash_including(
++              sticky: true,
++              name:   "pending",
++              title:  "Waiting",
++              text:   "Waiting for something",
++              icon:   "/tmp/wait.png"
++            )
++          )
++
++          subject.notify(
++            "Waiting for something",
++            type: :pending,
++            title: "Waiting",
++            image: "/tmp/wait.png",
++            sticky: true
++          )
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/growl_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/growl_spec.rb
+@@ -0,0 +1,167 @@
++require "notiffany/notifier/growl"
++
++module Notiffany
++  RSpec.describe Notifier::Growl do
++    module FakeGrowl
++      def self.notify(_message, _opts)
++      end
++
++      def self.installed?
++      end
++
++      class Base
++        def self.switches
++          [:sticky, :priority, :name, :title, :image]
++        end
++      end
++    end
++    let(:growl) { FakeGrowl }
++
++    let(:options) { {} }
++    let(:os) { "solaris" }
++    subject { described_class.new(options) }
++
++    before do
++      allow(Kernel).to receive(:require)
++      allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++
++      stub_const "Growl", growl
++      allow(growl).to receive(:installed?).and_return(true)
++      allow(growl).to receive(:notify)
++    end
++
++    describe "#initialize" do
++      context "host is not supported" do
++        let(:os) { "mswin" }
++
++        it "fails" do
++          expect { subject }.to raise_error(Notifier::Base::UnavailableError)
++        end
++      end
++
++      context "host is supported" do
++        let(:os) { "darwin" }
++
++        it "works" do
++          subject
++        end
++
++        context "when Growl is not installed" do
++          before do
++            allow(growl).to receive(:installed?).and_return(false)
++          end
++
++          it "fails" do
++            expect { subject }.to raise_error(Notifier::Base::UnavailableError)
++          end
++        end
++      end
++    end
++
++    describe "#notify" do
++      let(:os) { "darwin" }
++      context "with options passed at initialization" do
++        let(:options) { { title: "Hello", silent: true } }
++
++        it "uses these options by default" do
++          expect(growl).to receive(:notify).with(
++            "Welcome!",
++            hash_including(
++              sticky:   false,
++              priority: 0,
++              name:     "Notiffany",
++              title:    "Hello",
++              image:    "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify("Welcome!", image: "/tmp/welcome.png")
++        end
++
++        it "overwrites object options with passed options" do
++          expect(growl).to receive(:notify).with(
++            "Welcome!",
++            hash_including(
++              sticky:   false,
++              priority: 0,
++              name:     "Notiffany",
++              title:    "Welcome",
++              image:    "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify("Welcome!",
++                         title: "Welcome",
++                         image: "/tmp/welcome.png")
++        end
++      end
++
++      context "without additional options" do
++        it "shows the notification with the default options" do
++          expect(growl).to receive(:notify).with(
++            "Welcome!",
++            hash_including(
++              sticky:   false,
++              priority: 0,
++              name:     "Notiffany",
++              title:    "Welcome",
++              image:    "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify(
++            "Welcome!",
++            title: "Welcome",
++            image: "/tmp/welcome.png")
++        end
++      end
++
++      context "with additional options" do
++        it "can override the default options" do
++          expect(growl).to receive(:notify).with(
++            "Waiting for something",
++            hash_including(
++              sticky:   true,
++              priority: 2,
++              name:     "Notiffany",
++              title:    "Waiting",
++              image:    "/tmp/wait.png"
++            )
++          )
++
++          subject.notify(
++            "Waiting for something",
++            type: :pending,
++            title: "Waiting",
++            image: "/tmp/wait.png",
++            sticky:   true,
++            priority: 2
++          )
++        end
++      end
++
++      context "with options Growl cannot handle" do
++        it "passes options only Growl can handle" do
++          expect(growl).to receive(:notify).with(
++            "Foo",
++            sticky:   true,
++            priority: 2,
++            name:     "Notiffany",
++            title:    "Waiting",
++            image:    "/tmp/wait.png"
++          )
++
++          subject.notify(
++            "Foo",
++            foo: :bar,
++            type: :pending,
++            title: "Waiting",
++            image: "/tmp/wait.png",
++            sticky:   true,
++            priority: 2
++          )
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/libnotify_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/libnotify_spec.rb
+@@ -0,0 +1,120 @@
++require "notiffany/notifier/libnotify"
++
++module Notiffany
++  RSpec.describe Notifier::Libnotify do
++    let(:options) { {} }
++    let(:os) { "solaris" }
++    subject { described_class.new(options) }
++
++    before do
++      stub_const "Libnotify", double
++
++      allow(Kernel).to receive(:require)
++      allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++    end
++
++    describe "#initialize" do
++      let(:os) { "mswin" }
++      context "with unsupported host" do
++        it "does not require libnotify" do
++          expect(Kernel).to_not receive(:require)
++          expect { subject }.to raise_error(Notifier::Base::UnsupportedPlatform)
++        end
++      end
++
++      context "host is supported" do
++        let(:os) { "linux" }
++        it "requires libnotify" do
++          expect(Kernel).to receive(:require).and_return(true)
++          subject
++        end
++      end
++    end
++
++    describe "#notify" do
++      context "with options passed at initialization" do
++        let(:options) { { title: "Hello", silent: true } }
++
++        it "uses these options by default" do
++          expect(::Libnotify).to receive(:show).with(
++            hash_including(
++              transient: false,
++              append:    true,
++              timeout:   3,
++              urgency:   :low,
++              summary:   "Hello",
++              body:      "Welcome to Guard",
++              icon_path: "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify("Welcome to Guard", image: "/tmp/welcome.png")
++        end
++
++        it "overwrites object options with passed options" do
++          expect(::Libnotify).to receive(:show).with(
++            hash_including(
++              transient: false,
++              append:    true,
++              timeout:   3,
++              urgency:   :low,
++              summary:   "Welcome",
++              body:      "Welcome to Guard",
++              icon_path: "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify("Welcome to Guard",
++                         title: "Welcome",
++                         image: "/tmp/welcome.png")
++        end
++      end
++
++      context "without additional options" do
++        it "shows the notification with the default options" do
++          expect(::Libnotify).to receive(:show).with(
++            hash_including(
++              transient: false,
++              append:    true,
++              timeout:   3,
++              urgency:   :low,
++              summary:   "Welcome",
++              body:      "Welcome to Guard",
++              icon_path: "/tmp/welcome.png"
++            )
++          )
++
++          subject.notify("Welcome to Guard",
++                         title: "Welcome",
++                         image: "/tmp/welcome.png")
++        end
++      end
++
++      context "with additional options" do
++        it "can override the default options" do
++          expect(::Libnotify).to receive(:show).with(
++            hash_including(
++              transient: true,
++              append:    false,
++              timeout:   5,
++              urgency:   :critical,
++              summary:   "Waiting",
++              body:      "Waiting for something",
++              icon_path: "/tmp/wait.png"
++            )
++          )
++
++          subject.notify("Waiting for something",
++                         type: :pending,
++                         title: "Waiting",
++                         image: "/tmp/wait.png",
++                         transient: true,
++                         append:    false,
++                         timeout:   5,
++                         urgency:   :critical
++                        )
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/notifysend_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/notifysend_spec.rb
+@@ -0,0 +1,152 @@
++require "notiffany/notifier/notifysend"
++
++module Notiffany
++  class Notifier
++    RSpec.describe NotifySend do
++      let(:options) { {} }
++      let(:os) { "solaris" }
++      subject { described_class.new(options) }
++
++      let(:sheller) { class_double("Shellany::Sheller") }
++
++      before do
++        allow(Kernel).to receive(:require)
++        allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++
++        stub_const "NotifySend", double
++        stub_const("Shellany::Sheller", sheller)
++
++        allow(sheller).to receive(:stdout)
++      end
++
++      describe "#initialize" do
++        context "host is not supported" do
++          let(:os) { "mswin" }
++
++          it "do not check if the binary is available" do
++            expect(sheller).to_not receive(:stdout)
++            expect { subject }.to raise_error(Base::UnsupportedPlatform)
++          end
++        end
++
++        context "host is supported" do
++          let(:os) { "linux" }
++
++          describe 'check_available' do
++            it "checks if the binary is available" do
++              expect(sheller).to receive(:stdout).with("which notify-send").
++                and_return("foo\n")
++              subject
++            end
++
++            context 'binary check returns nil' do
++              before do
++                allow(sheller).to receive(:stdout).with("which notify-send").
++                  and_return(nil)
++              end
++
++              it 'should raise an UnavailableError' do
++                expect { subject }.to raise_error(Base::UnavailableError)
++              end
++            end
++          end
++        end
++      end
++
++      describe "#notify" do
++        before do
++          allow(sheller).to receive(:stdout).with("which notify-send").
++            and_return("foo\n")
++        end
++
++        context "with options passed at initialization" do
++          let(:options) { { image: "/tmp/hello.png", silent: true } }
++
++          it "uses these options by default" do
++            expect(sheller).to receive(:run) do |command, *arguments|
++              expect(command).to eql "notify-send"
++              expect(arguments).to include "-i", "/tmp/hello.png"
++              expect(arguments).to include "-u", "low"
++              expect(arguments).to include "-t", "3000"
++              expect(arguments).to include "-h", "int:transient:1"
++            end
++
++            subject.notify("Welcome")
++          end
++
++          it "overwrites object options with passed options" do
++            expect(sheller).to receive(:run) do |command, *arguments|
++              expect(command).to eql "notify-send"
++              expect(arguments).to include "-i", "/tmp/welcome.png"
++              expect(arguments).to include "-u", "low"
++              expect(arguments).to include "-t", "3000"
++              expect(arguments).to include "-h", "int:transient:1"
++            end
++
++            subject.notify("Welcome", image: "/tmp/welcome.png")
++          end
++
++          it "uses the title provided in the options" do
++            expect(sheller).to receive(:run) do |command, *arguments|
++              expect(command).to eql "notify-send"
++              expect(arguments).to include "Welcome"
++              expect(arguments).to include "test title"
++            end
++            subject.notify("Welcome", title: "test title")
++          end
++
++          it "converts notification type failed to normal urgency" do
++            expect(sheller).to receive(:run) do |command, *arguments|
++              expect(command).to eql "notify-send"
++              expect(arguments).to include "-u", "normal"
++            end
++
++            subject.notify("Welcome", type: :failed)
++          end
++
++          it "converts notification type pending to low urgency" do
++            expect(sheller).to receive(:run) do |command, *arguments|
++              expect(command).to eql "notify-send"
++              expect(arguments).to include "-u", "low"
++            end
++
++            subject.notify("Welcome", type: :pending)
++          end
++        end
++
++        context "without additional options" do
++          it "shows the notification with the default options" do
++            expect(sheller).to receive(:run) do |command, *arguments|
++              expect(command).to eql "notify-send"
++              expect(arguments).to include "-i", "/tmp/welcome.png"
++              expect(arguments).to include "-u", "low"
++              expect(arguments).to include "-t", "3000"
++              expect(arguments).to include "-h", "int:transient:1"
++            end
++
++            subject.notify("Welcome", image: "/tmp/welcome.png")
++          end
++        end
++
++        context "with additional options" do
++          it "can override the default options" do
++            expect(sheller).to receive(:run) do |command, *arguments|
++              expect(command).to eql "notify-send"
++              expect(arguments).to include "-i", "/tmp/wait.png"
++              expect(arguments).to include "-u", "critical"
++              expect(arguments).to include "-t", "5"
++            end
++
++            subject.notify(
++              "Waiting for something",
++              type: :pending,
++              image: "/tmp/wait.png",
++              t: 5,
++              u: :critical
++            )
++          end
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/rb_notifu_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/rb_notifu_spec.rb
+@@ -0,0 +1,131 @@
++require "notiffany/notifier/rb_notifu"
++
++module Notiffany
++  class Notifier
++    RSpec.describe Notifu do
++      let(:options) { { title: "Hello" } }
++      let(:os) { "solaris" }
++      subject { described_class.new(options) }
++
++      before do
++        allow(Kernel).to receive(:require)
++        allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++
++        stub_const "Notifu", double
++      end
++
++      describe "#initialize" do
++        context "host is not supported" do
++          let(:os) { "darwin" }
++
++          it "fails" do
++            expect { subject }.to raise_error(Base::UnsupportedPlatform)
++          end
++        end
++
++        context "host is supported" do
++          let(:os) { "mswin" }
++
++          it "requires rb-notifu" do
++            expect(Kernel).to receive(:require).with("rb-notifu")
++            subject
++          end
++        end
++      end
++
++      describe "#notify" do
++        let(:os) { "mswin" }
++
++        context "with options passed at initialization" do
++          it "uses these options by default" do
++            expect(::Notifu).to receive(:show).with(
++              time:    3,
++              icon:    false,
++              baloon:  false,
++              nosound: false,
++              noquiet: false,
++              xp:      false,
++              title:   "Hello",
++              type:    :info,
++              image:   "/tmp/welcome.png",
++              message: "Welcome to Guard"
++            )
++
++            subject.notify("Welcome to Guard", image: "/tmp/welcome.png")
++          end
++
++          it "overwrites object options with passed options" do
++            expect(::Notifu).to receive(:show).with(
++              hash_including(
++                time:    3,
++                icon:    false,
++                baloon:  false,
++                nosound: false,
++                noquiet: false,
++                xp:      false,
++                title:   "Welcome",
++                type:    :info,
++                image:   "/tmp/welcome.png",
++                message: "Welcome to Guard"
++              )
++            )
++
++            subject.notify("Welcome to Guard",
++                           title: "Welcome",
++                           image: "/tmp/welcome.png")
++          end
++        end
++
++        context "without additional options" do
++          it "shows the notification with the default options" do
++            expect(::Notifu).to receive(:show).with(
++              time:    3,
++              icon:    false,
++              baloon:  false,
++              nosound: false,
++              noquiet: false,
++              xp:      false,
++              title:   "Welcome",
++              type:    :info,
++              image:   "/tmp/welcome.png",
++              message: "Welcome to Guard"
++            )
++
++            subject.notify("Welcome to Guard",
++                           title: "Welcome",
++                           image: "/tmp/welcome.png")
++          end
++        end
++
++        context "with additional options" do
++          it "can override the default options" do
++            expect(::Notifu).to receive(:show).with(
++              time:    5,
++              icon:    true,
++              baloon:  true,
++              nosound: true,
++              noquiet: true,
++              xp:      true,
++              title:   "Waiting",
++              type:    :warn,
++              image:   "/tmp/wait.png",
++              message: "Waiting for something"
++            )
++
++            subject.notify("Waiting for something",
++                           time:    5,
++                           icon:    true,
++                           baloon:  true,
++                           nosound: true,
++                           noquiet: true,
++                           xp:      true,
++                           title:   "Waiting",
++                           type:    :pending,
++                           image:   "/tmp/wait.png"
++                          )
++          end
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/terminal_notifier_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/terminal_notifier_spec.rb
+@@ -0,0 +1,92 @@
++require "notiffany/notifier/terminal_notifier"
++
++module Notiffany
++  RSpec.describe Notifier::TerminalNotifier do
++    let(:options) { {} }
++    let(:os) { "solaris" }
++    subject { described_class.new(options) }
++
++    before do
++      allow(Kernel).to receive(:require)
++      allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++
++      stub_const "TerminalNotifier::Guard", double(available?: true)
++    end
++
++    describe ".available?" do
++      context "host is not supported" do
++        let(:os) { "mswin" }
++
++        it "fails" do
++          expect { subject }.to raise_error(Notifier::Base::UnavailableError)
++        end
++      end
++
++      context "host is supported" do
++        let(:os) { "darwin" }
++        it "works" do
++          subject
++        end
++      end
++    end
++
++    describe "#notify" do
++      let(:os) { "darwin" }
++      context "with options passed at initialization" do
++        let(:options) { { title: "Hello", silent: true } }
++
++        it "uses these options by default" do
++          expect(TerminalNotifier::Guard).to receive(:execute).
++            with(false, title: "Hello", type: :success, message: "any message")
++
++          subject.notify("any message")
++        end
++
++        it "overwrites object options with passed options" do
++          expect(::TerminalNotifier::Guard).to receive(:execute).
++            with(
++              false,
++              title: "Welcome",
++              type: :success,
++              message: "any message")
++
++          subject.notify("any message", title: "Welcome")
++        end
++      end
++
++      it "should call the notifier." do
++        expect(::TerminalNotifier::Guard).to receive(:execute).
++          with(false,
++               title: "any title",
++               type: :success,
++               message: "any message")
++
++        subject.notify("any message", title: "any title")
++      end
++
++      it "should allow the title to be customized" do
++        expect(::TerminalNotifier::Guard).to receive(:execute).
++          with(false,
++               title: "any title",
++               message: "any message",
++               type: :error)
++
++        subject.notify("any message", type: :error, title: "any title")
++      end
++
++      context "without a title set" do
++        it "should show the app name in the title" do
++          expect(::TerminalNotifier::Guard).to receive(:execute).
++            with(false,
++                 title: "FooBar Success",
++                 type: :success,
++                 message: "any message")
++
++          # TODO: why would anyone set the title explicitly to nil? and also
++          # expect it to be set to a default value?
++          subject.notify("any message", title: nil, app_name: "FooBar")
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/terminal_title_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/terminal_title_spec.rb
+@@ -0,0 +1,38 @@
++require "notiffany/notifier/terminal_title"
++
++RSpec.describe Notiffany::Notifier::TerminalTitle do
++  let(:options) { { title: "Hello" } }
++  let(:os) { "solaris" }
++  subject { described_class.new(options) }
++
++  before do
++    allow(Kernel).to receive(:require)
++    allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++  end
++
++  describe "#notify" do
++    context "with options passed at initialization" do
++      it "uses these options by default" do
++        expect(STDOUT).to receive(:puts).with("\e]2;[Hello] first line\a")
++        subject.notify("first line\nsecond line\nthird")
++      end
++
++      it "overwrites object options with passed options" do
++        expect(STDOUT).to receive(:puts).with("\e]2;[Welcome] first line\a")
++        subject.notify("first line\nsecond line\nthird", title: "Welcome")
++      end
++    end
++
++    it "set title + first line of message to terminal title" do
++      expect(STDOUT).to receive(:puts).with("\e]2;[any title] first line\a")
++      subject.notify("first line\nsecond line\nthird", title: "any title")
++    end
++  end
++
++  describe ".turn_off" do
++    it "clears the terminal title" do
++      expect(STDOUT).to receive(:puts).with("\e]2;\a")
++      subject.turn_off
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier/tmux_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier/tmux_spec.rb
+@@ -0,0 +1,592 @@
++require "notiffany/notifier/tmux"
++
++module Notiffany
++  class Notifier
++    RSpec.describe Tmux::Client do
++      let(:sheller) { class_double("Shellany::Sheller") }
++
++      subject { described_class.new(nil) }
++
++      before do
++        stub_const("Shellany::Sheller", sheller)
++      end
++
++      describe "#clients" do
++        context "when :all is given" do
++          subject { described_class.new(:all) }
++
++          it "removes null terminal" do
++            allow(sheller).to receive(:stdout).
++              with("tmux list-clients -F '\#{client_tty}'") do
++              "/dev/ttys001\n/dev/ttys000\n(null)\n"
++            end
++
++            clients = subject.clients
++
++            expect(clients).to include "/dev/ttys001"
++            expect(clients).to include "/dev/ttys000"
++            expect(clients).not_to include "(null)"
++          end
++        end
++      end
++
++      describe "#display" do
++        it "displays text in given area" do
++          expect(sheller).to receive(:run).with("tmux display 'foo'")
++          subject.display_message("foo")
++        end
++
++        context "when displaying on all clients" do
++          subject { described_class.new(:all) }
++
++          it "displays on every client" do
++            allow(sheller).to receive(:stdout).
++              with("tmux list-clients -F '\#{client_tty}'") do
++              "/dev/ttys001\n"
++            end
++
++            expect(sheller).to receive(:run)
++              .with("tmux display -c /dev/ttys001 'foo'")
++            subject.display_message("foo")
++          end
++        end
++      end
++
++      describe "#message_fg=" do
++        it "sets message fg color" do
++          expect(sheller).to receive(:run).with("tmux set -q message-fg green")
++          subject.message_fg = "green"
++        end
++      end
++
++      describe "#message_bg=" do
++        it "sets message bg color" do
++          expect(sheller).to receive(:run).with("tmux set -q message-bg white")
++          subject.message_bg = "white"
++        end
++      end
++
++      describe "#display_time=" do
++        it "sets display time" do
++          expect(sheller).to receive(:run).with("tmux set -q display-time 5000")
++          subject.display_time = 5000
++        end
++      end
++
++      describe "#title=" do
++        it "sets terminal title" do
++          expect(sheller).to receive(:run).
++            with("tmux set -q set-titles-string 'foo'")
++          subject.title = "foo"
++        end
++      end
++    end
++
++    RSpec.describe Tmux::Session do
++      let(:all) { instance_double(Tmux::Client) }
++      let(:tty) { instance_double(Tmux::Client) }
++      let(:sheller) { class_double("Shellany::Sheller") }
++
++      before do
++        allow(Tmux::Client).to receive(:new).with(:all).and_return(all)
++        allow(Tmux::Client).to receive(:new).with("tty").and_return(tty)
++        stub_const("Shellany::Sheller", sheller)
++      end
++
++      describe "#start" do
++        before do
++          allow(all).to receive(:clients).and_return(%w(tty))
++          allow(tty).to receive(:parse_options).and_return({})
++        end
++
++        it "sets options" do
++          subject
++        end
++      end
++
++      describe "#close" do
++        before do
++          allow(all).to receive(:clients).and_return(%w(tty))
++          allow(tty).to receive(:parse_options).and_return({})
++        end
++
++        it "restores the tmux options" do
++          allow(tty).to receive(:unset).with("status-left-bg", nil)
++          allow(tty).to receive(:unset).with("status-left-fg", nil)
++          allow(tty).to receive(:unset).with("status-right-bg", nil)
++          allow(tty).to receive(:unset).with("status-right-fg", nil)
++          allow(tty).to receive(:unset).with("message-bg", nil)
++          allow(tty).to receive(:unset).with("message-fg", nil)
++          allow(tty).to receive(:unset).with("display-time", nil)
++          allow(tty).to receive(:unset).with("display-time", nil)
++          subject.close
++        end
++      end
++    end
++
++    RSpec.describe Tmux do
++      let(:tmux_version) { 1.7 }
++
++      let(:options) { {} }
++      let(:os) { "solaris" }
++      let(:tmux_env) { true }
++      subject { described_class.new(options) }
++      let(:version) { 1.7 }
++
++      let(:client) { instance_double(Tmux::Client) }
++      let(:session) { instance_double(Tmux::Session) }
++
++      let(:sheller) { class_double("Shellany::Sheller") }
++
++      before do
++        allow(Kernel).to receive(:require)
++        allow(RbConfig::CONFIG).to receive(:[]).with("host_os") { os }
++
++        allow(ENV).to receive(:key?).with("TMUX").and_return(tmux_env)
++
++        allow(Tmux::Client).to receive(:new).and_return(client)
++        allow(Tmux::Client).to receive(:version).and_return(version)
++
++        allow(Tmux::Session).to receive(:new).and_return(session)
++        allow(session).to receive(:close)
++
++        stub_const("Shellany::Sheller", sheller)
++      end
++
++      after do
++        described_class.send(:_end_session) if described_class.send(:_session)
++      end
++
++      describe "#initialize" do
++        context "when the TMUX environment variable is set" do
++          let(:tmux_env) { true }
++
++          context "with a recent version of tmux" do
++            let(:version) { 1.8 }
++            it "works" do
++              subject
++            end
++          end
++
++          context "with an outdated version of tmux" do
++            let(:version) { 1.6 }
++            it "fails" do
++              expect { subject }.
++                to raise_error(
++                  Base::UnavailableError,
++                  /way too old \(1.6\)/
++                )
++            end
++          end
++        end
++
++        context "when the TMUX environment variable is not set" do
++          let(:tmux_env) { false }
++          it "fails" do
++            expect { subject }.
++              to raise_error(
++                Base::UnavailableError,
++                /only available inside a TMux session/
++              )
++          end
++        end
++      end
++
++      describe "#notify" do
++        before do
++          allow(client).to receive(:set).with("status-left-bg", anything)
++          allow(client).to receive(:display_time=)
++          allow(client).to receive(:message_fg=)
++          allow(client).to receive(:message_bg=)
++          allow(client).to receive(:display_message)
++        end
++
++        context "with options passed at initialization" do
++          let(:options) do
++            { success: "rainbow",
++              silent: true,
++              starting: "vanilla" }
++          end
++
++          it "uses these options by default" do
++            expect(client).to receive(:set).with("status-left-bg", "rainbow")
++            subject.notify("any message", type: :success)
++          end
++
++          it "overwrites object options with passed options" do
++            expect(client).to receive(:set).with("status-left-bg", "black")
++            subject.notify("any message", type: :success, success: "black")
++          end
++
++          it "uses the initialization options for custom types by default" do
++            expect(client).to receive(:set).with("status-left-bg", "vanilla")
++            subject.notify("any message", type: :starting)
++          end
++        end
++
++        it "sets the tmux status bar color to green on success" do
++          expect(client).to receive(:set).with("status-left-bg", "green")
++          subject.notify("any message", type: :success)
++        end
++
++        context "when success: black is passed in as an option" do
++          let(:options) { { success: "black" } }
++
++          it "on success it sets the tmux status bar color to black" do
++            expect(client).to receive(:set).with("status-left-bg", "black")
++            subject.notify("any message", options.merge(type: :success))
++          end
++        end
++
++        it "sets the tmux status bar color to red on failure" do
++          expect(client).to receive(:set).with("status-left-bg", "red")
++          subject.notify("any message", type: :failed)
++        end
++
++        it "should set the tmux status bar color to yellow on pending" do
++          expect(client).to receive(:set).with("status-left-bg", "yellow")
++          subject.notify("any message", type: :pending)
++        end
++
++        it "sets the tmux status bar color to green on notify" do
++          expect(client).to receive(:set).with("status-left-bg", "green")
++          subject.notify("any message", type: :notify)
++        end
++
++        it "sets the tmux status bar color to default color on a custom type" do
++          expect(client).to receive(:set).with("status-left-bg", "black")
++          subject.notify("any message", type: :custom, default: "black")
++        end
++
++        it "sets the tmux status bar color to default color on a custom type" do
++          expect(client).to receive(:set).with("status-left-bg", "green")
++          subject.notify("any message", type: :custom)
++        end
++
++        it "sets the tmux status bar color to passed color on a custom type" do
++          expect(client).to receive(:set).with("status-left-bg", "black")
++          subject.notify("any message", type: :custom, custom: "black")
++        end
++
++        context "when right status bar is passed in as an option" do
++          it "should set the right tmux status bar color on success" do
++            expect(client).to receive(:set).with("status-right-bg", "green")
++            subject.notify("any message", color_location: "status-right-bg")
++          end
++        end
++
++        it "does not change colors when the change_color flag is disabled" do
++          expect(client).to_not receive(:set)
++          subject.notify("any message", change_color: false)
++        end
++
++        it "calls display_message if the display_message flag is set" do
++          expect(client).to receive(:display_message).
++            with("Notiffany - any message")
++
++          subject.notify("any message", type: :notify, display_message: true)
++        end
++
++        context "when the display_message flag is not set" do
++          it "does not call display_message" do
++            expect(client).to_not receive(:display_message)
++            subject.notify("any message")
++          end
++        end
++
++        it "calls display_title if the display_title flag is set" do
++          expect(client).to receive(:title=).with("Notiffany - any message")
++          subject.notify("any message", type: :notify, display_title: true)
++        end
++
++        it "does not call display_title if the display_title flag is not set" do
++          expect(client).to_not receive(:display)
++          subject.notify("any message")
++        end
++
++        context "when color_location is passed with an array" do
++          let(:options) do
++            { color_location: %w(status-left-bg pane-border-fg) }
++          end
++
++          it "should set the color on multiple tmux settings" do
++            expect(client).to receive(:set).with("status-left-bg", "green")
++            expect(client).to receive(:set).with("pane-border-fg", "green")
++            subject.notify("any message", options)
++          end
++        end
++
++        context "with display_title option" do
++          let(:options) do
++            {
++              success: "rainbow",
++              silent: true,
++              starting: "vanilla",
++              display_title: true
++            }
++          end
++
++          before do
++            allow(client).to receive(:title=)
++            allow(client).to receive(:set).with("status-left-bg", anything)
++          end
++
++          it "displays the title" do
++            expect(client).to receive(:title=).with("any title - any message")
++            subject.notify "any message", type: "success", title: "any title"
++          end
++
++          it "shows only the first line of the message" do
++            expect(client).to receive(:title=).with("any title - any message")
++            subject.notify(
++              "any message\nline two",
++              type: "success",
++              title: "any title"
++            )
++          end
++
++          context "with success message type options" do
++            it "formats the message" do
++              expect(client).to receive(:title=).
++                with("[any title] => any message")
++
++              subject.notify(
++                "any message\nline two",
++                options.merge(
++                  type: "success",
++                  title: "any title",
++                  success_title_format: "[%s] => %s",
++                  default_title_format: "(%s) -> %s"
++                )
++              )
++            end
++          end
++
++          context "with pending message type options" do
++            it "formats the message" do
++              expect(client).to receive(:title=).
++                with("[any title] === any message")
++              subject.notify(
++                "any message\nline two",
++                type: "pending",
++                title: "any title",
++                pending_title_format: "[%s] === %s",
++                default_title_format: "(%s) -> %s"
++              )
++            end
++          end
++
++          context "with failed message type options" do
++            it "formats the message" do
++              expect(client).to receive(:title=).
++                with("[any title] <=> any message")
++
++              subject.notify(
++                "any message\nline two",
++                type: "failed",
++                title: "any title",
++                failed_title_format: "[%s] <=> %s",
++                default_title_format: "(%s) -> %s"
++              )
++            end
++          end
++        end
++
++        it "sets the display-time" do
++          expect(client).to receive(:display_time=).with(3000)
++
++          subject.notify(
++            "any message",
++            type: "success",
++            display_message: true,
++            title: "any title",
++            timeout: 3)
++        end
++
++        it "displays the message" do
++          expect(client).to receive(:display_message).
++            with("any title - any message")
++
++          subject.notify(
++            "any message",
++            display_message: true,
++            type: "success",
++            title: "any title"
++          )
++        end
++
++        it "handles line-breaks" do
++          expect(client).to receive(:display_message).
++            with("any title - any message xx line two")
++
++          subject.notify(
++            "any message\nline two",
++            type: "success",
++            display_message: true,
++            title: "any title",
++            line_separator: " xx ")
++        end
++
++        context "with success message type options" do
++          it "formats the message" do
++            expect(client).to receive(:display_message).
++              with("[any title] => any message - line two")
++
++            subject.notify(
++              "any message\nline two",
++              type: "success",
++              title: "any title",
++              display_message: true,
++              success_message_format: "[%s] => %s",
++              default_message_format: "(%s) -> %s")
++          end
++
++          it "sets the foreground color based on the type for success" do
++            allow(client).to receive(:message_fg=).with("green")
++
++            subject.notify(
++              "any message",
++              type: "success",
++              title: "any title",
++              display_message: true,
++              success_message_color: "green")
++          end
++
++          it "sets the background color" do
++            allow(client).to receive(:set).with("status-left-bg", :blue)
++            allow(client).to receive(:message_bg=).with("blue")
++
++            subject.notify(
++              "any message",
++              type: "success",
++              title: "any title",
++              success: :blue)
++          end
++        end
++
++        context "with pending message type options" do
++          let(:notify_opts) do
++            {
++              type: "pending",
++              title: "any title",
++              display_message: true
++            }
++          end
++
++          before do
++          end
++
++          it "formats the message" do
++            # expect(sheller).to receive(:run).
++            #  with("tmux display"\
++            #       ' \'\'').once {}
++            #
++            expect(client).to receive(:display_message).
++              with("[any title] === any message - line two")
++
++            subject.notify(
++              "any message\nline two",
++              notify_opts.merge(
++                pending_message_format: "[%s] === %s",
++                default_message_format: "(%s) -> %s")
++            )
++          end
++
++          it "sets the foreground color" do
++            expect(client).to receive(:message_fg=).with("blue")
++
++            subject.notify(
++              "any message",
++              notify_opts.merge(pending_message_color: "blue")
++            )
++          end
++
++          it "sets the background color" do
++            expect(client).to receive(:message_bg=).with(:white)
++            subject.notify("any message", notify_opts.merge(pending: :white))
++          end
++        end
++
++        context "with failed message type options" do
++          let(:notify_opts) do
++            {
++              type: "failed",
++              title: "any title",
++              display_message: true,
++              failed_message_color: "red"
++            }
++          end
++
++          before do
++            allow(client).to receive(:set).with("status-left-bg", anything)
++            allow(client).to receive(:message_fg=)
++            allow(client).to receive(:message_bg=)
++            allow(client).to receive(:display_message)
++          end
++
++          it "formats the message" do
++            expect(client).to receive(:display_message).
++              with("[any title] <=> any message - line two")
++
++            subject.notify(
++              "any message\nline two",
++              notify_opts.merge(
++                failed_message_format: "[%s] <=> %s",
++                default_message_format: "(%s) -> %s")
++            )
++          end
++
++          it "sets the foreground color" do
++            expect(client).to receive(:message_fg=).with("red")
++            subject.notify("any message", notify_opts)
++          end
++
++          it "sets the background color" do
++            expect(client).to receive(:message_bg=).with(:black)
++            subject.notify("any message", notify_opts.merge(failed: :black))
++          end
++        end
++      end
++
++      describe "#turn_on" do
++        context "when on" do
++          before do
++            subject.turn_on
++          end
++
++          it "fails" do
++            expect do
++              subject.turn_on
++            end.to raise_error("Already turned on!")
++          end
++        end
++      end
++
++      describe "#turn_off" do
++        context "when on" do
++          before do
++            subject.turn_on
++          end
++
++          it "closes the session" do
++            expect(session).to receive(:close)
++            subject.turn_off
++          end
++        end
++
++        context "when off" do
++          before do
++            subject.turn_on
++            subject.turn_off
++          end
++
++          it "fails" do
++            expect do
++              subject.turn_off
++            end.to raise_error("Already turned off!")
++          end
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/lib/notiffany/notifier_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/lib/notiffany/notifier_spec.rb
+@@ -0,0 +1,416 @@
++require "notiffany/notifier"
++
++module Notiffany
++  RSpec.describe Notifier, exclude_stubs: [Nenv, Notifier::Env] do
++    let(:options) { { notify: enabled } }
++    subject { described_class.new(options) }
++
++    let(:logger) { instance_double(Logger, :level= => nil, debug: nil) }
++    let(:enabled) { true }
++
++    # Use tmux as base, because it has both :turn_on and :turn_off
++    %w(foo bar baz).each do |name|
++      let(name.to_sym) do
++        class_double(
++          "Notiffany::Notifier::Tmux",
++          name: name
++        )
++      end
++    end
++
++    let(:foo_object) { instance_double("Notiffany::Notifier::Tmux") }
++    let(:bar_object) { instance_double("Notiffany::Notifier::Tmux") }
++
++    let(:env) { instance_double(Notifier::Env) }
++    let(:detected) { instance_double("Notiffany::Notifier::Detected") }
++
++    before do
++      allow(Notifier::Env).to receive(:new).with("notiffany").and_return(env)
++
++      allow(Logger).to receive(:new).and_return(logger)
++
++      # DEFAULTS FOR TESTS
++      allow(env).to receive(:notify?).and_return(true)
++      allow(env).to receive(:notify_active?).and_return(false)
++      allow(env).to receive(:notify_active=)
++      allow(env).to receive(:notify_pid).and_return($$)
++      allow(env).to receive(:notify_pid=).with($$)
++
++      allow(described_class::Detected).to receive(:new).
++        with(described_class::SUPPORTED, 'notiffany', logger).
++        and_return(detected)
++
++      allow(detected).to receive(:add)
++      allow(detected).to receive(:reset)
++      allow(detected).to receive(:detect)
++      allow(detected).to receive(:available).and_return([foo_object])
++
++      allow(foo_object).to receive(:title).and_return("Foo")
++      allow(bar_object).to receive(:title).and_return("Bar")
++    end
++
++    after do
++      # This is ok, because it shows singletons are NOT ok
++      described_class.instance_variable_set(:@detected, nil)
++    end
++
++    describe "#initialize" do
++      before do
++        allow(env).to receive(:notify?).and_return(env_enabled)
++      end
++
++      context "when enabled with environment" do
++        let(:env_enabled) { true }
++
++        context "when enabled with options" do
++          let(:options) { { notify: true } }
++          it "assigns a pid" do
++            expect(env).to receive(:notify_pid=).with($$)
++            subject
++          end
++
++          it "autodetects" do
++            expect(detected).to receive(:detect)
++            subject
++          end
++        end
++
++        context "when no options given" do
++          let(:options) { {} }
++          it "assigns a pid" do
++            expect(env).to receive(:notify_pid=).with($$)
++            subject
++          end
++
++          it "autodetects" do
++            expect(detected).to receive(:detect)
++            subject
++          end
++        end
++
++        context "when disabled with options" do
++          let(:options) { { notify: false } }
++          it "assigns a pid anyway" do
++            expect(env).to receive(:notify_pid=).with($$)
++            subject
++          end
++
++          it "does not autodetect" do
++            expect(detected).to_not receive(:detect)
++            subject
++          end
++        end
++      end
++
++      context "when disabled with environment" do
++        let(:env_enabled) { false }
++        pending
++      end
++
++      context "with custom notifier config" do
++        let(:env_enabled) { true }
++        let(:notifiers) { { foo: { bar: :baz } } }
++        let(:options) { { notifiers: notifiers } }
++
++        before do
++          allow(detected).to receive(:available).and_return([])
++          allow(env).to receive(:notify?).and_return(enabled)
++        end
++
++        context "when child process" do
++          let(:enabled) { true }
++          before { allow(env).to receive(:notify_pid).and_return($$ + 100) }
++          it "works" do
++            subject
++          end
++        end
++
++        context "when not connected" do
++          context "when disabled" do
++            let(:enabled) { false }
++
++            it "does not add anything" do
++              expect(detected).to_not receive(:add)
++              subject
++            end
++          end
++
++          context "when enabled" do
++            let(:enabled) { true }
++
++            context "when supported" do
++              let(:name) { foo }
++
++              context "when available" do
++                it "adds the notifier to the notifications" do
++                  expect(detected).to receive(:add).with(:foo, bar: :baz)
++                  subject
++                end
++              end
++            end
++          end
++        end
++
++        context "when connected" do
++          before do
++            allow(env).to receive(:notify?).and_return(enabled)
++          end
++
++          context "when disabled" do
++            let(:enabled) { false }
++
++            it "does not add anything" do
++              expect(detected).to_not receive(:add)
++              subject
++            end
++          end
++
++          context "when enabled" do
++            let(:enabled) { true }
++
++            context "when :off" do
++              let(:notifiers) { { off: {} } }
++              it "turns off the notifier" do
++                expect(subject).to_not be_active
++              end
++            end
++
++            context "when supported" do
++              let(:name) { foo }
++
++              context "when available" do
++                it "adds the notifier to the notifications" do
++                  expect(detected).to receive(:add).
++                    with(:foo, bar: :baz)
++                  subject
++                end
++              end
++            end
++          end
++        end
++      end
++    end
++
++    describe ".disconnect" do
++      before do
++        allow(env).to receive(:notify_pid=)
++      end
++
++      it "resets detector" do
++        expect(detected).to receive(:reset)
++        subject.disconnect
++      end
++
++      it "reset the pid env var" do
++        expect(env).to receive(:notify_pid=).with(nil)
++        subject.disconnect
++      end
++    end
++
++    describe ".turn_on" do
++      let(:options) { {} }
++
++      before do
++        allow(detected).to receive(:available).and_return(available)
++
++        subject
++        allow(env).to receive(:notify_active?).and_return(true)
++        subject.turn_off
++        allow(env).to receive(:notify_active?).and_return(false)
++      end
++
++      context "with available notifiers" do
++        let(:available) { [foo_object] }
++
++        context "when a child process" do
++          before { allow(env).to receive(:notify_pid).and_return($$ + 100) }
++          it { expect { subject.turn_on }.to raise_error(/Only notify()/) }
++        end
++
++        context "without silent option" do
++          let(:options) { { silent: false } }
++          it "shows the used notifications" do
++            expect(logger).to receive(:debug).
++              with "Notiffany is using Foo to send notifications."
++            subject.turn_on(options)
++          end
++        end
++
++        context "with silent option" do
++          let(:options) { { silent: true } }
++          it "does not show activated notifiers" do
++            expect(logger).to_not receive(:info)
++            subject.turn_on(options)
++          end
++        end
++      end
++
++      context "without available notifiers" do
++        let(:available) { [] }
++        it "sets mode to active" do
++          expect(env).to receive(:notify_active=).with(true)
++          subject.turn_on(options)
++        end
++      end
++    end
++
++    describe ".turn_off" do
++      before do
++        allow(env).to receive(:notify?).and_return(true)
++
++        allow(detected).to receive(:available).and_return(available)
++      end
++
++      context "with no available notifiers" do
++        let(:available) { [] }
++        it "is not active" do
++          subject
++          expect(subject).to_not be_active
++        end
++      end
++
++      context "with available notifiers" do
++        let(:available) { [foo_object] }
++
++        before do
++          subject
++        end
++
++        context "when a child process" do
++          before { allow(env).to receive(:notify_pid).and_return($$ + 100) }
++          it { expect { subject.turn_off }.to raise_error(/Only notify()/) }
++        end
++
++        it "turns off each notifier" do
++          allow(env).to receive(:notify_active?).and_return(true)
++          expect(foo_object).to receive(:turn_off)
++          subject.turn_off
++        end
++      end
++    end
++
++    describe ".enabled?" do
++      before do
++        allow(env).to receive(:notify?).and_return(enabled)
++      end
++
++      context "when enabled" do
++        let(:enabled) { true }
++        it { is_expected.to be_enabled }
++      end
++
++      context "when disabled" do
++        let(:enabled) { false }
++        it { is_expected.not_to be_enabled }
++      end
++    end
++
++    describe ".notify" do
++      context "with multiple notifiers" do
++        before do
++          allow(detected).to receive(:available).
++            and_return([foo_object, bar_object])
++
++          allow(foo).to receive(:new).with(color: true).and_return(foo_object)
++          allow(bar).to receive(:new).with({}).and_return(bar_object)
++          allow(env).to receive(:notify?).and_return(enabled)
++        end
++
++        # TODO: deprecate
++        context "when not connected" do
++          let(:enabled) { true }
++
++          before do
++            allow(env).to receive(:notify_active?).and_return(false)
++          end
++
++          context "when a child process" do
++            before { allow(env).to receive(:notify_pid).and_return($$ + 100) }
++
++            before do
++              allow(foo_object).to receive(:notify)
++              allow(bar_object).to receive(:notify)
++            end
++
++            it "sends notifications" do
++              expect(foo_object).to receive(:notify).with("Hello", foo: "bar")
++              expect(bar_object).to receive(:notify).with("Hello", foo: "bar")
++              subject.notify("Hello", foo: "bar")
++            end
++
++            it "shows a deprecation message" do
++              pending
++              expect(logger).to receive(:deprecation).
++                with(/Notifier.notify\(\) without a prior Notifier.connect/)
++
++              subject.notify("Hello", foo: "bar")
++            end
++          end
++        end
++
++        context "when connected" do
++          before do
++            subject
++            allow(env).to receive(:notify_active?).and_return(enabled)
++          end
++
++          context "when enabled" do
++            let(:enabled) { true }
++
++            it "sends notifications" do
++              expect(foo_object).to receive(:notify).with("Hello", foo: "bar")
++              expect(bar_object).to receive(:notify).with("Hello", foo: "bar")
++              subject.notify("Hello", foo: "bar")
++            end
++
++            context "when a child process" do
++              before { allow(env).to receive(:notify_pid).and_return($$ + 100) }
++              it "sends notifications" do
++                expect(foo_object).to receive(:notify).with("Hello", foo: "bar")
++                expect(bar_object).to receive(:notify).with("Hello", foo: "bar")
++                subject.notify("Hello", foo: "bar")
++              end
++            end
++          end
++
++          context "when disabled" do
++            let(:enabled) { false }
++
++            it "does not send notifications" do
++              expect(foo_object).to_not receive(:notify)
++              expect(bar_object).to_not receive(:notify)
++              subject.notify("Hi to everyone")
++            end
++
++            context "when a child process" do
++              before { allow(env).to receive(:notify_pid).and_return($$ + 100) }
++              it "sends notifications" do
++                expect(foo_object).to_not receive(:notify)
++                expect(bar_object).to_not receive(:notify)
++                subject.notify("Hello", foo: "bar")
++              end
++            end
++          end
++        end
++      end
++    end
++
++    describe "#available" do
++      context "when connected" do
++        let(:options) { { notify: true } }
++        before do
++          subject
++          allow(env).to receive(:notify_active?).and_return(true)
++          allow(detected).to receive(:available).and_return(available)
++        end
++
++        context "with available notifiers" do
++          let(:available) { [foo_object, bar_object] }
++          it "returns a list of available notifier info" do
++            expect(subject.available).to eq([foo_object, bar_object])
++          end
++        end
++      end
++    end
++  end
++end
+Index: ruby-notiffany/spec/notiffany_spec.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/notiffany_spec.rb
+@@ -0,0 +1,5 @@
++RSpec.describe Notiffany do
++  it 'has a version number' do
++    expect(Notiffany::VERSION).not_to be nil
++  end
++end
+Index: ruby-notiffany/spec/spec_helper.rb
+===================================================================
+--- /dev/null
++++ ruby-notiffany/spec/spec_helper.rb
+@@ -0,0 +1,24 @@
++RSpec.configure do |config|
++  config.expect_with :rspec do |expectations|
++    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
++  end
++
++  config.mock_with :rspec do |mocks|
++    mocks.verify_partial_doubles = true
++  end
++
++  config.filter_run :focus
++  config.run_all_when_everything_filtered = true
++
++  config.disable_monkey_patching!
++
++  config.warnings = true
++
++  config.default_formatter = 'doc' if config.files_to_run.one?
++
++  # config.profile_examples = 10
++
++  config.order = :random
++
++  Kernel.srand config.seed
++end
diff --git a/debian/patches/fix-uninitialized-constant-notiffany-version.patch b/debian/patches/fix-uninitialized-constant-notiffany-version.patch
new file mode 100644
index 0000000..cf3512c
--- /dev/null
+++ b/debian/patches/fix-uninitialized-constant-notiffany-version.patch
@@ -0,0 +1,15 @@
+Description: Fix "uninitialized constant Notiffany::VERSION" test failure
+Author: jackorp
+Origin: upstream, commit: c77ef974a9ae42de0f589ae73f1f8b33e2221fed
+Last-Update: 2017-11-16
+
+Index: ruby-notiffany/spec/notiffany_spec.rb
+===================================================================
+--- ruby-notiffany.orig/spec/notiffany_spec.rb
++++ ruby-notiffany/spec/notiffany_spec.rb
+@@ -1,3 +1,5 @@
++require 'notiffany/version'
++
+ RSpec.describe Notiffany do
+   it 'has a version number' do
+     expect(Notiffany::VERSION).not_to be nil
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..2a4d218
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,3 @@
+add-specs.patch
+fix-uninitialized-constant-notiffany-version.patch
+fix-images-path.patch
diff --git a/debian/ruby-tests.rake b/debian/ruby-tests.rake
new file mode 100644
index 0000000..cf1591e
--- /dev/null
+++ b/debian/ruby-tests.rake
@@ -0,0 +1,5 @@
+require 'gem2deb/rake/spectask'
+
+Gem2Deb::Rake::RSpecTask.new do |spec|
+  spec.pattern = './spec/**/*_spec.rb'
+end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-notiffany.git



More information about the Pkg-ruby-extras-commits mailing list