summaryrefslogtreecommitdiffhomepage
path: root/test/stylesheet/tc_styles.rb
blob: 29d37a3a59581c10b73954416fde2b18d911af3f (plain)
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
# frozen_string_literal: true

require 'tc_helper'

class TestStyles < Test::Unit::TestCase
  def setup
    @styles = Axlsx::Styles.new
  end

  def teardown; end

  def test_valid_document
    schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD))
    doc = Nokogiri::XML(@styles.to_xml_string)
    errors = []
    schema.validate(doc).each do |error|
      errors.push error
      puts error.message
    end

    assert_empty(errors)
  end

  def test_add_style_border_hash
    border_count = @styles.borders.size
    @styles.add_style border: { style: :thin, color: "FFFF0000" }

    assert_equal(@styles.borders.size, border_count + 1)
    assert_equal("FFFF0000", @styles.borders.last.prs.last.color.rgb)
    assert_raise(ArgumentError) { @styles.add_style border: { color: "FFFF0000" } }
    assert_equal(4, @styles.borders.last.prs.size)
  end

  def test_add_style_border_array
    prev_border_count = @styles.borders.size

    borders_array = [
      { style: :thin, color: "DDDDDD" },
      { edges: [:top], style: :thin, color: "000000" },
      { edges: [:bottom], style: :thick, color: "FF0000" },
      { edges: [:left], style: :dotted, color: "FFFF00" },
      { edges: [:right], style: :dashed, color: "FFFFFF" },
      { style: :thick, color: "CCCCCC" }
    ]

    @styles.add_style(border: borders_array)

    assert_equal(@styles.borders.size, (prev_border_count + 1))

    current_border = @styles.borders.last

    borders_array.each do |b_opts|
      next unless b_opts[:edges]

      border_pr = current_border.prs.detect { |x| x.name == b_opts[:edges].first }

      assert_equal(border_pr.color.rgb, "FF#{b_opts[:color]}")
    end
  end

  def test_add_style_border_edges
    @styles.add_style border: { style: :thin, color: "0000FFFF", edges: [:top, :bottom] }
    parts = @styles.borders.last.prs

    parts.each { |pr| assert_equal("0000FFFF", pr.color.rgb, "Style is applied to #{pr.name} properly") }
    assert_equal(2, (parts.map { |pr| pr.name.to_s }.sort && ['bottom', 'top']).size, "specify two edges, and you get two border prs")
  end

  def test_do_not_alter_options_in_add_style
    # This should test all options, but for now - just the bits that we know caused some pain
    options = { border: { style: :thin, color: "FF000000" } }
    @styles.add_style options

    assert_equal(:thin, options[:border][:style], 'thin style is stil in option')
    assert_equal("FF000000", options[:border][:color], 'color is stil in option')
  end

  def test_parse_num_fmt
    f_code = { format_code: "YYYY/MM" }
    num_fmt = { num_fmt: 5 }

    assert_nil(@styles.parse_num_fmt_options, 'noop if neither :format_code or :num_fmt exist')
    max = @styles.numFmts.map(&:numFmtId).max
    @styles.parse_num_fmt_options(f_code)

    assert_equal(@styles.numFmts.last.numFmtId, max + 1, "new numfmts gets next available id")
    assert(@styles.parse_num_fmt_options(num_fmt).is_a?(Integer), "Should return the provided num_fmt if not dxf")
    assert(@styles.parse_num_fmt_options(num_fmt.merge({ type: :dxf })).is_a?(Axlsx::NumFmt), "Makes a new NumFmt if dxf")
  end

  def test_parse_border_options_hash_required_keys
    assert_raise(ArgumentError, "Require color key") { @styles.parse_border_options(border: { style: :thin }) }
    assert_raise(ArgumentError, "Require style key") { @styles.parse_border_options(border: { color: "FF0d0d0d" }) }
    assert_nothing_raised { @styles.parse_border_options(border: { style: :thin, color: "FF000000" }) }
  end

  def test_parse_border_basic_options
    b_opts = { border: { diagonalUp: 1, edges: [:left, :right], color: "FFDADADA", style: :thick } }
    b = @styles.parse_border_options b_opts

    assert(b.is_a?(Integer))
    assert_equal(@styles.parse_border_options(b_opts.merge({ type: :dxf })).class, Axlsx::Border)
    assert_equal(1, @styles.borders.last.diagonalUp, "border options are passed in to the initializer")
  end

  def test_parse_border_options_edges
    b_opts = { border: { diagonalUp: 1, edges: [:left, :right], color: "FFDADADA", style: :thick } }
    @styles.parse_border_options b_opts
    b = @styles.borders.last
    left = b.prs.find { |bpr| bpr.name == :left }
    right = b.prs.find { |bpr| bpr.name == :right }
    top = b.prs.find { |bpr| bpr.name == :top }
    bottom = b.prs.find { |bpr| bpr.name == :bottom }

    assert_nil(top, "unspecified top edge should not be created")
    assert_nil(bottom, "unspecified bottom edge should not be created")
    assert(left.is_a?(Axlsx::BorderPr), "specified left edge is set")
    assert(right.is_a?(Axlsx::BorderPr), "specified right edge is set")
    assert_equal(left.style, right.style, "edge parts have the same style")
    assert_equal(:thick, left.style, "the style is THICK")
    assert_equal(right.color.rgb, left.color.rgb, "edge parts are colors are the same")
    assert_equal("FFDADADA", right.color.rgb, "edge color rgb is correct")
  end

  def test_parse_border_options_noop
    assert_nil(@styles.parse_border_options({}), "noop if the border key is not in options")
  end

  def test_parse_border_options_integer_xf
    assert_equal(1, @styles.parse_border_options(border: 1))
    assert_raise(ArgumentError, "unknown border index") { @styles.parse_border_options(border: 100) }
  end

  def test_parse_border_options_integer_dxf
    b_opts = { border: { edges: [:left, :right], color: "FFFFFFFF", style: :thick } }
    b = @styles.parse_border_options(b_opts)
    b2 = @styles.parse_border_options(border: b, type: :dxf)

    assert(b2.is_a?(Axlsx::Border), "Cloned existing border object")
  end

  def test_parse_alignment_options
    assert_nil(@styles.parse_alignment_options, "noop if :alignment is not set")
    assert(@styles.parse_alignment_options(alignment: {}).is_a?(Axlsx::CellAlignment))
  end

  def test_parse_font_using_defaults
    original = @styles.fonts.first
    @styles.add_style b: 1, sz: 99
    created = @styles.fonts.last
    original_attributes = Axlsx.instance_values_for(original)

    assert_equal(1, created.b)
    assert_equal(99, created.sz)
    attributes_to_reject = %w(b sz)
    copied = original_attributes.reject { |key, _value| attributes_to_reject.include? key }
    instance_vals = Axlsx.instance_values_for(created)

    copied.each do |key, value|
      assert_equal(instance_vals[key], value)
    end
  end

  def test_parse_font_options
    options = {
      fg_color: "FF050505",
      sz: 20,
      b: 1,
      i: 1,
      u: :single,
      strike: 1,
      outline: 1,
      shadow: 1,
      charset: 9,
      family: 1,
      font_name: "woot font"
    }

    assert_nil(@styles.parse_font_options, "noop if no font keys are set")
    assert(@styles.parse_font_options(b: 1).is_a?(Integer), "return index of font if not :dxf type")
    assert_equal(@styles.parse_font_options(b: 1, type: :dxf).class, Axlsx::Font, "return font object if :dxf type")

    f = @styles.parse_font_options(options.merge(type: :dxf))
    color = options.delete(:fg_color)
    options[:name] = options.delete(:font_name)

    options.each do |key, value|
      assert_equal(f.send(key), value, "assert that #{key} was parsed")
    end
    assert_equal(f.color.rgb, color)
  end

  def test_parse_fill_options
    assert_nil(@styles.parse_fill_options, "noop if no fill keys are set")
    assert(@styles.parse_fill_options(bg_color: "DE").is_a?(Integer), "return index of fill if not :dxf type")
    assert_equal(@styles.parse_fill_options(bg_color: "DE", type: :dxf).class, Axlsx::Fill, "return fill object if :dxf type")
    f = @styles.parse_fill_options(bg_color: "DE", type: :dxf)

    assert_equal("FFDEDEDE", f.fill_type.bgColor.rgb)
  end

  def test_parse_protection_options
    assert_nil(@styles.parse_protection_options, "noop if no protection keys are set")
    assert_equal(@styles.parse_protection_options(hidden: 1).class, Axlsx::CellProtection, "creates a new cell protection object")
  end

  def test_add_style
    fill_count = @styles.fills.size
    font_count = @styles.fonts.size
    xf_count = @styles.cellXfs.size

    @styles.add_style bg_color: "FF000000", fg_color: "FFFFFFFF", sz: 13, num_fmt: Axlsx::NUM_FMT_PERCENT, alignment: { horizontal: :left }, border: Axlsx::STYLE_THIN_BORDER, hidden: true, locked: true

    assert_equal(@styles.fills.size, fill_count + 1)
    assert_equal(@styles.fonts.size, font_count + 1)
    assert_equal(@styles.cellXfs.size, xf_count + 1)
    xf = @styles.cellXfs.last

    assert_equal(xf.fillId, (@styles.fills.size - 1), "points to the last created fill")
    assert_equal("FF000000", @styles.fills.last.fill_type.fgColor.rgb, "fill created with color")

    assert_equal(xf.fontId, (@styles.fonts.size - 1), "points to the last created font")
    assert_equal(13, @styles.fonts.last.sz, "font sz applied")
    assert_equal("FFFFFFFF", @styles.fonts.last.color.rgb, "font color applied")

    assert_equal(xf.borderId, Axlsx::STYLE_THIN_BORDER, "border id is set")
    assert_equal(xf.numFmtId, Axlsx::NUM_FMT_PERCENT, "number format id is set")

    assert(xf.alignment.is_a?(Axlsx::CellAlignment), "alignment was created")
    assert_equal(:left, xf.alignment.horizontal, "horizontal alignment applied")
    assert(xf.protection.hidden, "hidden protection set")
    assert(xf.protection.locked, "cell locking set")
    assert_raise(ArgumentError, "should reject invalid borderId") { @styles.add_style border: 2 }

    assert(xf.applyProtection, "protection applied")
    assert(xf.applyBorder, "border applied")
    assert(xf.applyNumberFormat, "number format applied")
    assert(xf.applyAlignment, "alignment applied")
  end

  def test_basic_add_style_dxf
    border_count = @styles.borders.size
    @styles.add_style border: { style: :thin, color: "FFFF0000" }, type: :dxf

    assert_equal(@styles.borders.size, border_count, "styles borders not affected")
    assert_equal("FFFF0000", @styles.dxfs.last.border.prs.last.color.rgb)
    assert_raise(ArgumentError) { @styles.add_style border: { color: "FFFF0000" }, type: :dxf }
    assert_equal(4, @styles.borders.last.prs.size)
  end

  def test_add_style_dxf
    fill_count = @styles.fills.size
    font_count = @styles.fonts.size
    dxf_count = @styles.dxfs.size

    style = @styles.add_style bg_color: "FF000000", fg_color: "FFFFFFFF", sz: 13, alignment: { horizontal: :left }, border: { style: :thin, color: "FFFF0000" }, hidden: true, locked: true, type: :dxf

    assert_equal(@styles.dxfs.size, dxf_count + 1)
    assert_equal(0, style, "returns the zero-based dxfId")

    dxf = @styles.dxfs.last

    assert_equal("FF000000", @styles.dxfs.last.fill.fill_type.bgColor.rgb, "fill created with color")

    assert_equal(font_count, @styles.fonts.size, "font not created under styles")
    assert_equal(fill_count, @styles.fills.size, "fill not created under styles")

    assert(dxf.border.is_a?(Axlsx::Border), "border is set")
    assert_nil(dxf.numFmt, "number format is not set")

    assert(dxf.alignment.is_a?(Axlsx::CellAlignment), "alignment was created")
    assert_equal(:left, dxf.alignment.horizontal, "horizontal alignment applied")
    assert(dxf.protection.hidden, "hidden protection set")
    assert(dxf.protection.locked, "cell locking set")
    assert_raise(ArgumentError, "should reject invalid borderId") { @styles.add_style border: 3 }
  end

  def test_multiple_dxf
    # add a second style
    style = @styles.add_style bg_color: "00000000", fg_color: "FFFFFFFF", sz: 13, alignment: { horizontal: :left }, border: { style: :thin, color: "FFFF0000" }, hidden: true, locked: true, type: :dxf

    assert_equal(0, style, "returns the first dxfId")
    style = @styles.add_style bg_color: "FF000000", fg_color: "FFFFFFFF", sz: 13, alignment: { horizontal: :left }, border: { style: :thin, color: "FFFF0000" }, hidden: true, locked: true, type: :dxf

    assert_equal(1, style, "returns the second dxfId")
  end

  def test_valid_document_with_font_options
    font_options = {
      fg_color: "FF050505",
      sz: 20,
      b: 1,
      i: 1,
      u: :single,
      strike: 1,
      outline: 1,
      shadow: 1,
      charset: 9,
      family: 1,
      font_name: "woot font"
    }
    @styles.add_style font_options

    schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD))
    doc = Nokogiri::XML(@styles.to_xml_string)
    errors = []
    schema.validate(doc).each do |error|
      errors.push error
      puts error.message
    end

    assert_empty(errors)
  end

  def test_border_top_without_border_regression
    ### https://github.com/axlsx-styler-gem/axlsx_styler/issues/31

    borders = {
      top: { style: :double, color: '0000FF' },
      right: { style: :thick, color: 'FF0000' },
      bottom: { style: :double, color: '0000FF' },
      left: { style: :thick, color: 'FF0000' }
    }

    borders.each do |edge, b_opts|
      @styles.add_style("border_#{edge}".to_sym => b_opts)

      current_border = @styles.borders.last

      border_pr = current_border.prs.detect { |x| x.name == edge }

      assert_equal(border_pr.color.rgb, "FF#{b_opts[:color]}")
    end
  end
end