caxlsx 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +126 -31
  3. data/README.md +78 -170
  4. data/examples/{image1.jpeg → assets/image1.jpeg} +0 -0
  5. data/examples/generate.rb +15 -0
  6. data/lib/axlsx.rb +2 -3
  7. data/lib/axlsx/drawing/bar_chart.rb +3 -3
  8. data/lib/axlsx/drawing/bar_series.rb +3 -5
  9. data/lib/axlsx/drawing/d_lbls.rb +1 -1
  10. data/lib/axlsx/drawing/pie_series.rb +1 -1
  11. data/lib/axlsx/drawing/series_title.rb +3 -1
  12. data/lib/axlsx/drawing/title.rb +3 -2
  13. data/lib/axlsx/package.rb +53 -19
  14. data/lib/axlsx/rels/relationship.rb +26 -25
  15. data/lib/axlsx/stylesheet/font.rb +10 -2
  16. data/lib/axlsx/util/constants.rb +2 -1
  17. data/lib/axlsx/util/mime_type_utils.rb +1 -1
  18. data/lib/axlsx/util/validators.rb +2 -2
  19. data/lib/axlsx/util/zip_command.rb +73 -0
  20. data/lib/axlsx/version.rb +1 -1
  21. data/lib/axlsx/workbook/workbook.rb +0 -9
  22. data/lib/axlsx/workbook/worksheet/cell.rb +32 -5
  23. data/lib/axlsx/workbook/worksheet/col.rb +8 -4
  24. data/lib/axlsx/workbook/worksheet/data_validation.rb +4 -4
  25. data/lib/axlsx/workbook/worksheet/pivot_table.rb +7 -2
  26. data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +1 -1
  27. data/lib/axlsx/workbook/worksheet/rich_text_run.rb +1 -1
  28. data/lib/axlsx/workbook/worksheet/row.rb +6 -3
  29. data/lib/axlsx/workbook/worksheet/table.rb +1 -1
  30. data/lib/axlsx/workbook/worksheet/worksheet.rb +17 -4
  31. data/lib/caxlsx.rb +2 -0
  32. data/test/drawing/tc_drawing.rb +2 -2
  33. data/test/drawing/tc_hyperlink.rb +1 -1
  34. data/test/drawing/tc_one_cell_anchor.rb +1 -1
  35. data/test/drawing/tc_pic.rb +4 -4
  36. data/test/drawing/tc_pie_series.rb +2 -1
  37. data/test/drawing/tc_series_title.rb +21 -0
  38. data/test/drawing/tc_title.rb +16 -0
  39. data/test/fixtures/image1.gif +0 -0
  40. data/test/fixtures/image1.jpeg +0 -0
  41. data/test/fixtures/image1.jpg +0 -0
  42. data/test/fixtures/image1.png +0 -0
  43. data/test/fixtures/image1_fake.jpg +0 -0
  44. data/test/rels/tc_relationship.rb +8 -0
  45. data/test/stylesheet/tc_font.rb +14 -2
  46. data/test/stylesheet/tc_styles.rb +27 -1
  47. data/test/tc_axlsx.rb +6 -0
  48. data/test/tc_helper.rb +0 -2
  49. data/test/tc_package.rb +82 -13
  50. data/test/util/tc_mime_type_utils.rb +1 -1
  51. data/test/util/tc_validators.rb +1 -1
  52. data/test/workbook/worksheet/tc_cell.rb +68 -2
  53. data/test/workbook/worksheet/tc_col.rb +16 -1
  54. data/test/workbook/worksheet/tc_pivot_table.rb +8 -0
  55. data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +8 -0
  56. data/test/workbook/worksheet/tc_rich_text_run.rb +3 -2
  57. data/test/workbook/worksheet/tc_row.rb +38 -0
  58. data/test/workbook/worksheet/tc_table.rb +10 -0
  59. data/test/workbook/worksheet/tc_worksheet.rb +24 -15
  60. metadata +130 -151
  61. data/examples/2010_comments.rb +0 -17
  62. data/examples/anchor_swapping.rb +0 -28
  63. data/examples/auto_filter.rb +0 -25
  64. data/examples/basic_charts.rb +0 -58
  65. data/examples/chart_colors.rb +0 -88
  66. data/examples/colored_links.rb +0 -59
  67. data/examples/conditional_formatting/example_conditional_formatting.rb +0 -89
  68. data/examples/conditional_formatting/getting_barred.rb +0 -37
  69. data/examples/conditional_formatting/hitting_the_high_notes.rb +0 -37
  70. data/examples/conditional_formatting/scaled_colors.rb +0 -39
  71. data/examples/conditional_formatting/stop_and_go.rb +0 -37
  72. data/examples/data_validation.rb +0 -67
  73. data/examples/example.rb +0 -885
  74. data/examples/extractive.rb +0 -45
  75. data/examples/ios_preview.rb +0 -14
  76. data/examples/merge_cells.rb +0 -17
  77. data/examples/no_grid_with_borders.rb +0 -18
  78. data/examples/page_setup.rb +0 -11
  79. data/examples/pivot_table.rb +0 -39
  80. data/examples/pivot_test.rb +0 -63
  81. data/examples/sheet_protection.rb +0 -10
  82. data/examples/skydrive/real_example.rb +0 -63
  83. data/examples/split.rb +0 -16
  84. data/examples/styles.rb +0 -66
  85. data/examples/underline.rb +0 -13
  86. data/examples/wrap_text.rb +0 -21
  87. data/lib/axlsx/util/parser.rb +0 -44
@@ -20,12 +20,13 @@ class TestPieSeries < Test::Unit::TestCase
20
20
  assert_raise(ArgumentError, "require valid explosion") { @series.explosion = :lots }
21
21
  assert_nothing_raised("allow valid explosion") { @series.explosion = 20 }
22
22
  assert(@series.explosion == 20)
23
+ # issue 58 - explosion caused to_xml_string to fail - now tested
24
+ assert_nothing_raised("allow to_xml_string") { @series.to_xml_string }
23
25
  end
24
26
 
25
27
  def test_to_xml_string
26
28
  doc = Nokogiri::XML(@series.to_xml_string)
27
29
  assert(doc.xpath("//srgbClr[@val='#{@series.colors[0]}']"))
28
-
29
30
  end
30
31
  #TODO test unique serialization parts
31
32
 
@@ -30,4 +30,25 @@ class TestSeriesTitle < Test::Unit::TestCase
30
30
  assert(@title.text == "one")
31
31
  end
32
32
 
33
+ def test_to_xml_string_for_special_characters
34
+ @chart.add_series(title: @title, data: [3, 7], labels: ['A', 'B'])
35
+
36
+ @title.text = "&><'\""
37
+
38
+ doc = Nokogiri::XML(@chart.to_xml_string)
39
+ errors = doc.errors
40
+ assert(errors.empty?, "invalid xml: #{errors.map(&:to_s).join(', ')}")
41
+ end
42
+
43
+ def test_to_xml_string_for_special_characters_in_cell
44
+ @chart.add_series(title: @title, data: [3, 7], labels: ['A', 'B'])
45
+
46
+ cell = @row.cells.first
47
+ cell.value = "&><'\""
48
+ @title.cell = cell
49
+
50
+ doc = Nokogiri::XML(@chart.to_xml_string)
51
+ errors = doc.errors
52
+ assert(errors.empty?, "invalid xml: #{errors.map(&:to_s).join(', ')}")
53
+ end
33
54
  end
@@ -51,4 +51,20 @@ class TestTitle < Test::Unit::TestCase
51
51
  assert_equal(1, doc.xpath('//c:v[text()="one"]').size)
52
52
  end
53
53
 
54
+ def test_to_xml_string_for_special_characters
55
+ @chart.title.text = "&><'\""
56
+ doc = Nokogiri::XML(@chart.to_xml_string)
57
+ errors = doc.errors
58
+ assert(errors.empty?, "invalid xml: #{errors.map(&:to_s).join(', ')}")
59
+ end
60
+
61
+ def test_to_xml_string_for_special_characters_in_cell
62
+ cell = @row.cells.first
63
+ cell.value = "&><'\""
64
+
65
+ @chart.title.cell = cell
66
+ doc = Nokogiri::XML(@chart.to_xml_string)
67
+ errors = doc.errors
68
+ assert(errors.empty?, "invalid xml: #{errors.map(&:to_s).join(', ')}")
69
+ end
54
70
  end
Binary file
Binary file
Binary file
Binary file
File without changes
@@ -13,6 +13,14 @@ class TestRelationships < Test::Unit::TestCase
13
13
  instance = Axlsx::Relationship.new(source_obj, Axlsx::WORKSHEET_R, 'target')
14
14
  assert_equal instance.Id, Axlsx::Relationship.new(source_obj, Axlsx::WORKSHEET_R, 'target').Id
15
15
  end
16
+
17
+ def test_ids_cache_is_thread_safe
18
+ cache1, cache2 = nil
19
+ t1 = Thread.new { cache1 = Axlsx::Relationship.ids_cache }
20
+ t2 = Thread.new { cache2 = Axlsx::Relationship.ids_cache }
21
+ [t1, t2].each(&:join)
22
+ assert_not_same(cache1, cache2)
23
+ end
16
24
 
17
25
  def test_target_is_only_considered_for_same_attributes_check_if_target_mode_is_external
18
26
  source_obj = Object.new
@@ -62,11 +62,23 @@ class TestFont < Test::Unit::TestCase
62
62
  assert_equal(@item.i, true)
63
63
  end
64
64
 
65
- # def u=(v) Axlsx::validate_boolean v; @u = v end
65
+ # def u=(v) Axlsx::validate_cell_u v; @u = v end
66
66
  def test_u
67
67
  assert_raise(ArgumentError) { @item.u = -7 }
68
+ assert_nothing_raised { @item.u = :single }
69
+ assert_equal(@item.u, :single)
70
+ doc = Nokogiri::XML(@item.to_xml_string)
71
+ assert(doc.xpath('//u[@val="single"]'))
72
+ end
73
+
74
+ def test_u_backward_compatibility
75
+ # backward compatibility for true
68
76
  assert_nothing_raised { @item.u = true }
69
- assert_equal(@item.u, true)
77
+ assert_equal(@item.u, :single)
78
+
79
+ # backward compatibility for false
80
+ assert_nothing_raised { @item.u = false }
81
+ assert_equal(@item.u, :none)
70
82
  end
71
83
 
72
84
  # def strike=(v) Axlsx::validate_boolean v; @strike = v end
@@ -124,7 +124,7 @@ class TestStyles < Test::Unit::TestCase
124
124
  :sz => 20,
125
125
  :b => 1,
126
126
  :i => 1,
127
- :u => 1,
127
+ :u => :single,
128
128
  :strike => 1,
129
129
  :outline => 1,
130
130
  :shadow => 1,
@@ -232,4 +232,30 @@ class TestStyles < Test::Unit::TestCase
232
232
  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
233
233
  assert_equal(1, style, "returns the second dxfId")
234
234
  end
235
+
236
+ def test_valid_document_with_font_options
237
+ font_options = {
238
+ :fg_color => "FF050505",
239
+ :sz => 20,
240
+ :b => 1,
241
+ :i => 1,
242
+ :u => :single,
243
+ :strike => 1,
244
+ :outline => 1,
245
+ :shadow => 1,
246
+ :charset => 9,
247
+ :family => 1,
248
+ :font_name => "woot font"
249
+ }
250
+ @styles.add_style font_options
251
+
252
+ schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD))
253
+ doc = Nokogiri::XML(@styles.to_xml_string)
254
+ errors = []
255
+ schema.validate(doc).each do |error|
256
+ errors.push error
257
+ puts error.message
258
+ end
259
+ assert(errors.size == 0)
260
+ end
235
261
  end
data/test/tc_axlsx.rb CHANGED
@@ -24,8 +24,14 @@ class TestAxlsx < Test::Unit::TestCase
24
24
 
25
25
 
26
26
  def test_trust_input_can_be_set_to_true
27
+ # Class variables like this are not reset between test runs, so we have
28
+ # to save and restore the original value manually.
29
+ old = Axlsx.trust_input
30
+
27
31
  Axlsx.trust_input = true
28
32
  assert_equal true, Axlsx.trust_input
33
+
34
+ Axlsx.trust_input = old
29
35
  end
30
36
  def test_cell_range_relative
31
37
  p = Axlsx::Package.new
data/test/tc_helper.rb CHANGED
@@ -8,5 +8,3 @@ end
8
8
  require 'test/unit'
9
9
  require "timecop"
10
10
  require "axlsx.rb"
11
- # MIME detection for Microsoft Office 2007+ formats
12
- require 'mimemagic/overlay'
data/test/tc_package.rb CHANGED
@@ -65,7 +65,7 @@ class TestPackage < Test::Unit::TestCase
65
65
  end
66
66
 
67
67
  @fname = 'axlsx_test_serialization.xlsx'
68
- img = File.expand_path('../../examples/image1.jpeg', __FILE__)
68
+ img = File.expand_path('../fixtures/image1.jpeg', __FILE__)
69
69
  ws.add_image(:image_src => img, :noSelect => true, :noMove => true, :hyperlink=>"http://axlsx.blogspot.com") do |image|
70
70
  image.width=720
71
71
  image.height=666
@@ -73,12 +73,12 @@ class TestPackage < Test::Unit::TestCase
73
73
  image.start_at 5, 5
74
74
  image.end_at 10, 10
75
75
  end
76
- ws.add_image :image_src => File.expand_path('../../examples/image1.gif', __FILE__) do |image|
76
+ ws.add_image :image_src => File.expand_path('../fixtures/image1.gif', __FILE__) do |image|
77
77
  image.start_at 0, 20
78
78
  image.width=360
79
79
  image.height=333
80
80
  end
81
- ws.add_image :image_src => File.expand_path('../../examples/image1.png', __FILE__) do |image|
81
+ ws.add_image :image_src => File.expand_path('../fixtures/image1.png', __FILE__) do |image|
82
82
  image.start_at 9, 20
83
83
  image.width = 180
84
84
  image.height = 167
@@ -127,18 +127,85 @@ class TestPackage < Test::Unit::TestCase
127
127
  end
128
128
 
129
129
  def test_serialization
130
- assert_nothing_raised do
131
- begin
132
- @package.serialize(@fname)
133
- zf = Zip::File.open(@fname)
134
- @package.send(:parts).each{ |part| zf.get_entry(part[:entry]) }
135
- File.delete(@fname)
136
- rescue Errno::EACCES
137
- puts "WARNING:: test_serialization requires write access."
138
- end
130
+ @package.serialize(@fname)
131
+ assert_zip_file_matches_package(@fname, @package)
132
+ assert_created_with_rubyzip(@fname, @package)
133
+ File.delete(@fname)
134
+ end
135
+
136
+ def test_serialization_with_zip_command
137
+ @package.serialize(@fname, zip_command: "zip")
138
+ assert_zip_file_matches_package(@fname, @package)
139
+ assert_created_with_zip_command(@fname, @package)
140
+ File.delete(@fname)
141
+ end
142
+
143
+ def test_serialization_with_zip_command_and_absolute_path
144
+ fname = "#{Dir.tmpdir}/#{@fname}"
145
+ @package.serialize(fname, zip_command: "zip")
146
+ assert_zip_file_matches_package(fname, @package)
147
+ assert_created_with_zip_command(fname, @package)
148
+ File.delete(fname)
149
+ end
150
+
151
+ def test_serialization_with_invalid_zip_command
152
+ assert_raises Axlsx::ZipCommand::ZipError do
153
+ @package.serialize(@fname, zip_command: "invalid_zip")
139
154
  end
140
155
  end
141
156
 
157
+ def assert_zip_file_matches_package(fname, package)
158
+ zf = Zip::File.open(fname)
159
+ package.send(:parts).each{ |part| zf.get_entry(part[:entry]) }
160
+ end
161
+
162
+ def assert_created_with_rubyzip(fname, package)
163
+ assert_equal 2098, get_mtime(fname, package).year, "XLSX files created with RubyZip have 2098 as the file mtime"
164
+ end
165
+
166
+ def assert_created_with_zip_command(fname, package)
167
+ assert_equal Time.now.utc.year, get_mtime(fname, package).year, "XLSX files created with a zip command have the current year as the file mtime"
168
+ end
169
+
170
+ def get_mtime(fname, package)
171
+ zf = Zip::File.open(fname)
172
+ part = package.send(:parts).first
173
+ entry = zf.get_entry(part[:entry])
174
+ entry.mtime.utc
175
+ end
176
+
177
+ def test_serialization_with_deprecated_argument
178
+ warnings = capture_warnings do
179
+ @package.serialize(@fname, false)
180
+ end
181
+ assert_equal 1, warnings.size
182
+ assert_includes warnings.first, "confirm_valid as a boolean is deprecated"
183
+ File.delete(@fname)
184
+ end
185
+
186
+ def test_serialization_with_deprecated_three_arguments
187
+ warnings = capture_warnings do
188
+ @package.serialize(@fname, true, zip_command: "zip")
189
+ end
190
+ assert_zip_file_matches_package(@fname, @package)
191
+ assert_created_with_zip_command(@fname, @package)
192
+ assert_equal 2, warnings.size
193
+ assert_includes warnings.first, "with 3 arguments is deprecated"
194
+ File.delete(@fname)
195
+ end
196
+
197
+ def capture_warnings(&block)
198
+ original_warn = Kernel.instance_method(:warn)
199
+ warnings = []
200
+ Kernel.send(:define_method, :warn) { |string| warnings << string }
201
+ block.call
202
+ original_verbose = $VERBOSE
203
+ $VERBOSE = nil
204
+ Kernel.send(:define_method, :warn, original_warn)
205
+ $VERBOSE = original_verbose
206
+ warnings
207
+ end
208
+
142
209
  # See comment for Package#zip_entry_for_part
143
210
  def test_serialization_creates_identical_files_at_any_time_if_created_at_is_set
144
211
  @package.core.created = Time.now
@@ -161,7 +228,7 @@ class TestPackage < Test::Unit::TestCase
161
228
  end
162
229
 
163
230
  def test_serialization_creates_files_with_excel_mime_type
164
- assert_equal(MimeMagic.by_magic(@package.to_stream).type,
231
+ assert_equal(Marcel::MimeType.for(@package.to_stream),
165
232
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
166
233
  end
167
234
 
@@ -236,6 +303,8 @@ class TestPackage < Test::Unit::TestCase
236
303
  # this is just a roundabout guess for a package as it is build now
237
304
  # in testing.
238
305
  assert(stream.size > 80000)
306
+ # Cached ids should be cleared
307
+ assert(Axlsx::Relationship.ids_cache.empty?)
239
308
  end
240
309
 
241
310
  def test_encrypt
@@ -1,7 +1,7 @@
1
1
  require 'tc_helper.rb'
2
2
  class TestMimeTypeUtils < Test::Unit::TestCase
3
3
  def setup
4
- @test_img = File.dirname(__FILE__) + "/../../examples/image1.jpeg"
4
+ @test_img = File.dirname(__FILE__) + "/../fixtures/image1.jpeg"
5
5
  end
6
6
 
7
7
  def teardown
@@ -127,7 +127,7 @@ class TestValidators < Test::Unit::TestCase
127
127
  assert_raise(ArgumentError) { Axlsx.validate_data_validation_error_style 0 }
128
128
 
129
129
  #data_validation_type
130
- [:custom, :data, :decimal, :list, :none, :textLength, :time, :whole].each do |sym|
130
+ [:custom, :data, :decimal, :list, :none, :textLength, :date, :time, :whole].each do |sym|
131
131
  assert_nothing_raised { Axlsx.validate_data_validation_type sym }
132
132
  end
133
133
  assert_raise(ArgumentError) { Axlsx.validate_data_validation_error_style :other_symbol }
@@ -8,7 +8,7 @@ class TestCell < Test::Unit::TestCase
8
8
  @ws = p.workbook.add_worksheet :name=>"hmmm"
9
9
  p.workbook.styles.add_style :sz=>20
10
10
  @row = @ws.add_row
11
- @c = @row.add_cell 1, :type=>:float, :style=>1
11
+ @c = @row.add_cell 1, :type=>:float, :style=>1, :escape_formulas=>true
12
12
  data = (0..26).map { |index| index }
13
13
  @ws.add_row data
14
14
  @cAA = @ws["AA2"]
@@ -19,6 +19,7 @@ class TestCell < Test::Unit::TestCase
19
19
  assert_equal(@c.type, :float, "type option is applied")
20
20
  assert_equal(@c.style, 1, "style option is applied")
21
21
  assert_equal(@c.value, 1.0, "type option is applied and value is casted")
22
+ assert_equal(@c.escape_formulas, true, "escape formulas option is applied")
22
23
  end
23
24
 
24
25
  def test_style_date_data
@@ -60,7 +61,7 @@ class TestCell < Test::Unit::TestCase
60
61
  def test_autowidth
61
62
  style = @c.row.worksheet.workbook.styles.add_style({:alignment => {:horizontal => :center, :vertical => :center, :wrap_text => true}} )
62
63
  @c.style = style
63
- assert_equal(@c.autowidth, 5.5)
64
+ assert_in_delta(6.6, @c.autowidth, 0.01)
64
65
  end
65
66
 
66
67
  def test_time
@@ -70,6 +71,13 @@ class TestCell < Test::Unit::TestCase
70
71
  assert_equal(@c.value, now.to_time)
71
72
  end
72
73
 
74
+ def test_date
75
+ @c.type = :date
76
+ now = Time.now
77
+ @c.value = now
78
+ assert_equal(@c.value, now.to_date)
79
+ end
80
+
73
81
  def test_style
74
82
  assert_raise(ArgumentError, "must reject invalid style indexes") { @c.style=@c.row.worksheet.workbook.styles.cellXfs.size }
75
83
  assert_nothing_raised("must allow valid style index changes") {@c.style=1}
@@ -99,6 +107,12 @@ class TestCell < Test::Unit::TestCase
99
107
 
100
108
  def test_cell_type_from_value
101
109
  assert_equal(@c.send(:cell_type_from_value, 1.0), :float)
110
+ assert_equal(@c.send(:cell_type_from_value, "1e1"), :float)
111
+ assert_equal(@c.send(:cell_type_from_value, "1e#{Float::MAX_10_EXP}"), :float)
112
+ assert_equal(@c.send(:cell_type_from_value, "1e#{Float::MAX_10_EXP + 1}"), :string)
113
+ assert_equal(@c.send(:cell_type_from_value, "1e-1"), :float)
114
+ assert_equal(@c.send(:cell_type_from_value, "1e#{Float::MIN_10_EXP}"), :float)
115
+ assert_equal(@c.send(:cell_type_from_value, "1e#{Float::MIN_10_EXP - 1}"), :string)
102
116
  assert_equal(@c.send(:cell_type_from_value, 1), :integer)
103
117
  assert_equal(@c.send(:cell_type_from_value, Date.today), :date)
104
118
  assert_equal(@c.send(:cell_type_from_value, Time.now), :time)
@@ -113,6 +127,31 @@ class TestCell < Test::Unit::TestCase
113
127
  assert_equal(:iso_8601, @c.send(:cell_type_from_value, '2008-08-30T01:45:36.123+09:00'))
114
128
  end
115
129
 
130
+ def test_cell_type_from_value_looks_like_number_but_is_not
131
+ mimic_number = Class.new do
132
+ def initialize(to_s_value)
133
+ @to_s_value = to_s_value
134
+ end
135
+
136
+ def to_s
137
+ @to_s_value
138
+ end
139
+ end
140
+
141
+ number_strings = [
142
+ '1',
143
+ '1234567890',
144
+ '1.0',
145
+ '1e1',
146
+ '0',
147
+ "1e#{Float::MIN_10_EXP}"
148
+ ]
149
+
150
+ number_strings.each do |number_string|
151
+ assert_equal(@c.send(:cell_type_from_value, mimic_number.new(number_string)), :string)
152
+ end
153
+ end
154
+
116
155
  def test_cast_value
117
156
  @c.type = :string
118
157
  assert_equal(@c.send(:cast_value, 1.0), "1.0")
@@ -321,6 +360,33 @@ class TestCell < Test::Unit::TestCase
321
360
  assert(doc.xpath("//f[text()='IF(2+2=4,4,5)']").any?)
322
361
  end
323
362
 
363
+ def test_to_xml_string_formula_escaped
364
+ p = Axlsx::Package.new
365
+ ws = p.workbook.add_worksheet do |sheet|
366
+ sheet.add_row ["=IF(2+2=4,4,5)"], escape_formulas: true
367
+ end
368
+ doc = Nokogiri::XML(ws.to_xml_string)
369
+ doc.remove_namespaces!
370
+ assert(doc.xpath("//t[text()='=IF(2+2=4,4,5)']").any?)
371
+ end
372
+
373
+ def test_to_xml_string_formula_escape_array_parameter
374
+ p = Axlsx::Package.new
375
+ ws = p.workbook.add_worksheet do |sheet|
376
+ sheet.add_row [
377
+ "=IF(2+2=4,4,5)",
378
+ "=IF(13+13=4,4,5)",
379
+ "=IF(99+99=4,4,5)"
380
+ ], escape_formulas: [true, false, true]
381
+ end
382
+ doc = Nokogiri::XML(ws.to_xml_string)
383
+ doc.remove_namespaces!
384
+
385
+ assert(doc.xpath("//t[text()='=IF(2+2=4,4,5)']").any?)
386
+ assert(doc.xpath("//f[text()='IF(13+13=4,4,5)']").any?)
387
+ assert(doc.xpath("//t[text()='=IF(99+99=4,4,5)']").any?)
388
+ end
389
+
324
390
  def test_to_xml_string_array_formula
325
391
  p = Axlsx::Package.new
326
392
  ws = p.workbook.add_worksheet do |sheet|