File: formatters_spec.rb

package info (click to toggle)
ruby-rspec 3.13.0c0e0m0s1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,856 kB
  • sloc: ruby: 70,868; sh: 1,423; makefile: 99
file content (234 lines) | stat: -rw-r--r-- 8,827 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
require 'pathname'

module RSpec::Core::Formatters
  RSpec.describe Loader do

    let(:output)   { StringIO.new }
    let(:reporter) { instance_double "Reporter", :register_listener => nil }
    let(:loader)   { Loader.new reporter }

    describe "#add(formatter)" do
      let(:path) { File.join(Dir.tmpdir, 'output.txt') }

      it "adds to the list of formatters" do
        loader.add :documentation, output
        expect(loader.formatters.first).to be_an_instance_of(DocumentationFormatter)
      end

      it "finds a formatter by name (w/ Symbol)" do
        loader.add :documentation, output
        expect(loader.formatters.first).to be_an_instance_of(DocumentationFormatter)
      end

      it "finds a formatter by name (w/ String)" do
        loader.add 'documentation', output
        expect(loader.formatters.first).to be_an_instance_of(DocumentationFormatter)
      end

      it "finds a formatter by class" do
        formatter_class = Class.new(BaseTextFormatter)
        Loader.formatters[formatter_class] = []
        loader.add formatter_class, output
        expect(loader.formatters.first).to be_an_instance_of(formatter_class)
      end

      it "finds a formatter by class name" do
        stub_const("CustomFormatter", Class.new(BaseFormatter))
        Loader.formatters[CustomFormatter] = []
        loader.add "CustomFormatter", output
        expect(loader.formatters.first).to be_an_instance_of(CustomFormatter)
      end

      it "lets you pass a formatter instance, for when you need to instantiate it with some custom state" do
        instance = ProgressFormatter.new(StringIO.new)

        expect {
          loader.add(instance)
        }.to change { loader.formatters }.from([]).to([instance])
      end

      context "when a legacy formatter is added with RSpec::LegacyFormatters" do
        formatter_class = Struct.new(:output)
        let(:formatter) { double "formatter", :notifications => notifications, :output => output }
        let(:notifications) { [:a, :b, :c] }

        before do
          class_double("RSpec::LegacyFormatters", :load_formatter => formatter).as_stubbed_const
        end

        it "loads formatters from the external gem" do
          loader.add formatter_class, output
          expect(loader.formatters).to eq [formatter]
        end

        it "subscribes the formatter to the notifications the adaptor implements" do
          expect(reporter).to receive(:register_listener).with(formatter, *notifications)
          loader.add formatter_class, output
        end

        it "will ignore duplicate legacy formatters" do
          loader.add formatter_class, output
          expect(reporter).to_not receive(:register_listener)
          expect {
            loader.add formatter_class, output
          }.not_to change { loader.formatters.length }
        end
      end

      context "when a legacy formatter is added without RSpec::LegacyFormatters" do
        formatter_class = Struct.new(:output)

        before do
          allow_deprecation
        end

        it "issues a deprecation" do
          expect_warn_deprecation(
            /The #{formatter_class} formatter uses the deprecated formatter interface.+#{__FILE__}:#{__LINE__ + 1}/)
          loader.add formatter_class, output
        end
      end

      it "finds a formatter by class fully qualified name" do
        stub_const("RSpec::CustomFormatter", (Class.new(BaseFormatter)))
        Loader.formatters[RSpec::CustomFormatter] = []
        loader.add "RSpec::CustomFormatter", output
        expect(loader.formatters.first).to be_an_instance_of(RSpec::CustomFormatter)
      end

      it "requires a formatter file based on its fully qualified name" do
        expect(loader).to receive(:require).with('rspec/custom_formatter') do
          stub_const("RSpec::CustomFormatter", (Class.new(BaseFormatter)))
          Loader.formatters[RSpec::CustomFormatter] = []
        end
        loader.add "RSpec::CustomFormatter", output
        expect(loader.formatters.first).to be_an_instance_of(RSpec::CustomFormatter)
      end

      it "raises NameError if class is unresolvable" do
        expect(loader).to receive(:require).with('rspec/custom_formatter3')
        expect { loader.add "RSpec::CustomFormatter3", output }.to raise_error(NameError)
      end

      it "raises ArgumentError if formatter is unknown" do
        expect { loader.add :nonexistent, output }.to raise_error(ArgumentError)
      end

      context "with a 2nd arg defining the output" do
        it "creates a file at that path and sets it as the output" do
          loader.add('doc', path)
          expect(loader.formatters.first.output).to be_a(File)
          expect(loader.formatters.first.output.path).to eq(path)
        end

        it "accepts Pathname objects for file paths" do
          pathname = Pathname.new(path)
          loader.add('doc', pathname)
          expect(loader.formatters.first.output).to be_a(File)
          expect(loader.formatters.first.output.path).to eq(path)
        end
      end

      context "when a duplicate formatter exists" do
        before { loader.add :documentation, output }

        it "doesn't add the formatter for the same output target" do
          expect(reporter).to_not receive(:register_listener)
          expect {
            loader.add :documentation, output
          }.not_to change { loader.formatters.length }
        end

        it "adds the formatter for different output targets" do
          expect {
            loader.add :documentation, path
          }.to change { loader.formatters.length }
        end

        plain_old_formatter = Class.new do
          RSpec::Core::Formatters.register self, :example_started

          def initialize(output)
          end
        end

        it "handles formatters which do not subclass our formatters" do
          expect {
            loader.add plain_old_formatter, output
          }.to change { loader.formatters.length }

          # deliberate duplicate to ensure we can check for them correctly
          expect {
            loader.add plain_old_formatter, output
          }.to_not change { loader.formatters.length }
        end
      end

      context "when a custom formatter exists" do
        specific_formatter = RSpec::Core::Formatters::JsonFormatter
        generic_formatter = specific_formatter.superclass

        before { loader.add generic_formatter, output }

        it "adds a subclass of that formatter for the same output target" do
          expect {
            loader.add specific_formatter, output
          }.to change { loader.formatters.length }
        end
      end
    end

    describe "#setup_default" do
      let(:setup_default) { loader.setup_default output, output }

      context "with a formatter that implements #message" do
        it 'doesnt add a fallback formatter' do
          allow(reporter).to receive(:registered_listeners).with(:message) { [:json] }
          setup_default
          expect(loader.formatters).to exclude(
            an_instance_of ::RSpec::Core::Formatters::FallbackMessageFormatter
          )
        end
      end

      context "without a formatter that implements #message" do
        it 'adds a fallback for message output' do
          allow(reporter).to receive(:registered_listeners).with(:message) { [] }
          expect {
            setup_default
          }.to change { loader.formatters }.
            from( excluding an_instance_of ::RSpec::Core::Formatters::FallbackMessageFormatter ).
            to( including an_instance_of ::RSpec::Core::Formatters::FallbackMessageFormatter )
        end
      end

      context "with profiling enabled" do
        before do
          allow(reporter).to receive(:registered_listeners).with(:message) { [:json] }
          allow(RSpec.configuration).to receive(:profile_examples?) { true }
        end

        context "without an existing profile formatter" do
          it "will add the profile formatter" do
            allow(reporter).to receive(:registered_listeners).with(:dump_profile) { [] }
            expect {
              setup_default
            }.to change { loader.formatters }.
              from( excluding an_instance_of ::RSpec::Core::Formatters::ProfileFormatter ).
              to( including an_instance_of ::RSpec::Core::Formatters::ProfileFormatter )
          end
        end

        context "when a formatter that implement #dump_profile is added" do
          it "wont add the profile formatter" do
            allow(reporter).to receive(:registered_listeners).with(:dump_profile) { [:json] }
            setup_default
            expect(
              loader.formatters.map(&:class)
            ).to_not include ::RSpec::Core::Formatters::ProfileFormatter
          end
        end
      end
    end
  end
end