-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathsquid_spec.rb
More file actions
342 lines (277 loc) · 11.8 KB
/
squid_spec.rb
File metadata and controls
342 lines (277 loc) · 11.8 KB
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
require 'spec_helper'
describe 'Prawn::Document#chart' do
let(:pdf) { Prawn::Document.new }
let(:chart) { pdf.chart(data, settings); pdf.render }
let(:data) { {} }
let(:options) { {legend: false, baseline: false, steps: 0, format: :currency} }
let(:settings) { options }
let(:blue_rgb) { [0.1804, 0.3412, 0.549] }
specify 'given no data, does not plot anything' do
expect(rectangles_of chart).to be_empty
end
context 'given series without values' do
let(:settings) { options.merge steps: 2 }
let(:data) { {series_1: {}, series_2: {}} }
it 'does not plot anything' do
expect(rectangles_of chart).to be_empty
end
end
context 'given one series' do
let(:values) { {2013 => 50, 2014 => -30, 2015 => 20} }
let(:data) { {series: values} }
it 'includes one column for each value of the series' do
expect(rectangles_of(chart).size).to be values.size
end
it 'has columns of the same width' do
widths = rectangles_of(chart).map{|r| r[:width]}
expect(widths.uniq).to be_one
end
it 'has all the columns aligned along the "0" value of the graph' do
y = rectangles_of(chart).map{|r| r[:point].last}
expect(y.uniq).to be_one
end
it 'has blue columns' do
expect(colors_of(chart).fill_color).to eq blue_rgb
end
it 'does not include value labels on top of the chart' do
expect(strings_of chart).to be_empty
end
context 'given the :label option is set to true' do
let(:settings) { options.merge label: true }
it 'includes the formatted value labels on top of each item' do
expect(strings_of chart).to eq %w($50.00 -$30.00 $20.00)
end
end
context 'given the series has nil values' do
let(:values) { {2013 => -50, 2014 => nil, 2015 => 20} }
it 'ignores nil values' do
expect(rectangles_of(chart).size).to be 2
end
end
context 'given the :type is set to :point' do
let(:settings) { options.merge type: :point }
it 'prints the elements as circles of the same radius' do
expect(rectangles_of chart).to be_empty
expect(circles_of chart).not_to be_empty
radii = points_of(chart).map{|x| x.map(&:first).inject(:-)}
expect(radii.uniq).to be_one
end
end
context 'given the :type is set to :line' do
let(:settings) { options.merge type: :line }
it 'prints the elements by connecting them with lines' do
expect(rectangles_of chart).to be_empty
expect(points_of(chart).size).to be values.size - 1
end
context 'given the :line_widths option is set to an array of values' do
let(:line_width) { 1 + rand(10) }
let(:settings) { options.merge type: :line, line_widths: [line_width] }
it 'draws the line with the given width' do
expect(lines_of(chart).widths).to include(line_width)
end
end
end
end
context 'given many series' do
let(:series_1) { {2013 => 110, 2014 => 30, 2015 => 13} }
let(:series_2) { {2013 => -50, 2014 => 10, 2015 => 53} }
let(:series_3) { {2013 => 20, 2014 => 140, 2015 => -3} }
let(:data) { {series_1: series_1, series_2: series_2, series_3: series_3} }
it 'includes one column for each value of each series' do
expect(rectangles_of(chart).size).to be 9
end
it 'has columns of the same width' do
widths = rectangles_of(chart).map{|r| r[:width]}
expect(widths.uniq).to be_one
end
context 'given the :labels option is set for some series' do
let(:settings) { options.merge labels: [true, false, true] }
it 'draws a value labels for each rectangle of those series' do
expect(strings_of(chart).size).to be 6
end
end
context 'given the :type is set to :point' do
let(:settings) { options.merge type: :point }
it 'prints the one circle for each value of each series' do
expect(rectangles_of chart).to be_empty
expect(circles_of(chart).size/28).to be 9
end
end
context 'given the :type is set to :line' do
let(:settings) { options.merge type: :line }
it 'includes one line for each series' do
expect(rectangles_of chart).to be_empty
expect(points_of(chart).size).to be 6
end
end
context 'given the :type is set to :stack' do
let(:settings) { options.merge type: :stack }
it 'includes one stacked rectangle for each value of each series' do
expect(rectangles_of(chart).size).to be 9
end
it 'includes as many stacks as the number of values' do
expect(rectangles_of(chart).map{|r| r[:point].first}.uniq.size).to be 3
end
end
context 'given multiple options are provided' do
let(:settings) { {type: :two_axis, colors: ['4ecdc4','c7f464','556270'], line_widths: [4, 2, 2]} }
it 'applies all the options successfully' do
expect(rectangles_of(chart).size).to be 9
end
end
end
context 'given non-default options' do
let(:values) { {2013 => 50, 2014 => -30, 2015 => 20} }
let(:data) { {'BWK p.a.' => values} }
describe 'shows/hides the chart with the :chart option' do
let(:settings) { options.merge chart: false }
it { expect(rectangles_of chart).to be_empty }
end
describe 'shows/hides the chart with Squid.configuration.chart' do
before { Squid.configure {|config| config.chart = false} }
after { Squid.configure {|config| config.chart = true} }
it { expect(rectangles_of chart).to be_empty }
end
describe 'shows/hides the legend with the :legend option' do
let(:settings) { options.merge legend: true }
it { expect(strings_of chart).not_to be_empty }
it { expect(strings_of chart).to include 'BWK p.a.' }
end
describe 'shows/hides the chart with Squid.configuration.chart' do
before { Squid.configure {|config| config.legend = false} }
after { Squid.configure {|config| config.legend = true} }
let(:settings) { options.except :legend }
it { expect(strings_of chart).to be_empty }
end
describe 'shows/hides the gridlines with the :step option' do
let(:settings) { options.merge steps: 8, chart: false }
it { expect(points_of(chart).size).to be 9 }
end
describe 'shows/hides the chart with Squid.configuration.chart' do
before { Squid.configure {|config| config.steps = 8} }
after { Squid.configure {|config| config.steps = 4} }
let(:settings) { options.merge(chart: false).except :steps }
it { expect(points_of(chart).size).to be 9 }
end
describe 'shows/hides the value labels with the :label option' do
let(:settings) { options.merge label: true }
it { expect(strings_of chart).not_to be_empty }
end
describe 'shows/hides the value labels with Squid.configuration.label' do
before { Squid.configure {|config| config.labels = [true]} }
after { Squid.configure {|config| config.labels = [false]} }
it { expect(strings_of chart).not_to be_empty }
end
describe 'shows/hides the ticks with the :ticks option' do
let(:settings) { options.merge baseline: true, ticks: true }
specify do
points = points_of chart
ticks_count = points.count{|tick| tick.first.last - tick.last.last == 2}
expect(ticks_count).to eq values.size
end
end
describe 'shows/hides the ticks with the Squid.configuration.ticks' do
before { Squid.configure {|config| config.ticks = true} }
after { Squid.configure {|config| config.ticks = false} }
let(:settings) { options.merge baseline: true }
specify do
points = points_of chart
ticks_count = points.count{|tick| tick.first.last - tick.last.last == 2}
expect(ticks_count).to eq values.size
end
end
describe 'uses the color provided with the :color option' do
let(:settings) { options.merge color: 'ff0000' }
it { expect(colors_of(chart).fill_color).to eq [1.0, 0.0, 0.0] }
end
describe 'uses the colors provided with the :colors option' do
let(:settings) { options.merge colors: [ %w(ff0000) ] }
it { expect(colors_of(chart).fill_color).to eq [1.0, 0.0, 0.0] }
end
describe 'uses the colors provided with Squid.configuration.colors' do
before { Squid.configure {|config| config.colors = ['ff0000']} }
after { Squid.configure {|config| config.colors = []} }
it { expect(colors_of(chart).fill_color).to eq [1.0, 0.0, 0.0] }
end
describe 'uses a given range with max and min options' do
let(:settings) { options.merge(steps: 5, max: 100, min: -100).except(:format) }
it { expect(strings_of chart).to eq ["100", "60", "20", "-20", "-60", "-100"] }
end
describe 'formats value labels with the value of the :format option' do
let(:settings) { options.merge label: true, format: :percentage }
it { expect(strings_of chart).to eq %w(50.0% -30.0% 20.0%) }
end
describe 'formats value labels with the value of the :formats option' do
let(:settings) { options.merge labels: [true], formats: [:percentage] }
it { expect(strings_of chart).to eq %w(50.0% -30.0% 20.0%) }
end
describe 'formats value labels with the values from Squid.configuration' do
before { Squid.configure {|config| config.labels = [true]; config.formats = [:percentage]} }
after { Squid.configure {|config| config.labels = []; config.formats = []} }
let(:settings) { options.except :format }
it { expect(strings_of chart).to eq %w(50.0% -30.0% 20.0%) }
end
describe 'uses the line width provided with the :line_width option' do
let(:settings) { options.merge type: :line, line_width: 6 }
it { expect(lines_of(chart).widths).to include(6) }
end
describe 'uses the line widths provided with the :line_widths option' do
let(:settings) { options.merge type: :line, line_widths: [ 6 ] }
it { expect(lines_of(chart).widths).to include(6) }
end
describe 'uses the line widths provided with Squid.configuration.line_widths' do
before { Squid.configure {|config| config.line_widths = [6]} }
after { Squid.configure {|config| config.line_widths = []} }
let(:settings) { options.merge type: :line }
it { expect(lines_of(chart).widths).to include(6) }
end
describe 'uses the type provided with the :type option' do
let(:settings) { options.merge type: :point }
it { expect(circles_of chart).not_to be_empty }
end
describe 'uses the type provided with Squid.configuration.type' do
before { Squid.configure {|config| config.type = :point} }
after { Squid.configure {|config| config.type = :column} }
it { expect(circles_of chart).not_to be_empty }
end
end
context 'given long data keys with narrow space' do
let(:settings) { options.merge every: 1, baseline: true }
let(:data) { {"Views per playlist start"=>
{"STORYTIME/MISC"=>1.2,
"PRANKS/CHALLENGES"=>1.3,
"SKITS"=>1.1,
"*MUSIC*"=>1.0,
"RELATIONSHIPS/ADVICE/TIPS"=>1.1,
"LOVE/LIFE/FAMILY FUN"=>1.1,
"TRAVEL VLOGS"=>1.1,
"FITNESS/WORKOUTS"=>1.1}} }
it 'does not raise Prawn::Errors::CannotFit error' do
expect { chart }.not_to raise_error
end
end
end
def rectangles_of(output)
PDF::Inspector::Graphics::Rectangle.analyze(output).rectangles
end
def colors_of(output)
PDF::Inspector::Graphics::Color.analyze(output)
end
def strings_of(output)
PDF::Inspector::Text.analyze(output).strings
end
def circles_of(output)
PDF::Inspector::Graphics::Curve.analyze(output).coords
end
def points_of(output)
lines_of(output).points.each_slice(2)
end
def lines_of(output)
PDF::Inspector::Graphics::Line.analyze(output)
end
# Monkey-patch so non-black colors can be analyzed at the end
class PDF::Inspector::Graphics::Color
def set_color_for_nonstroking_and_special(*params)
@fill_color = params unless params.all? &:zero?
end
end