diff options
| author | Luka Lüdicke <[email protected]> | 2020-11-26 19:48:33 +0100 |
|---|---|---|
| committer | Luka Lüdicke <[email protected]> | 2020-12-10 13:13:54 +0100 |
| commit | e859d267e9e4239a8f85253f1e303dc27ece0cb6 (patch) | |
| tree | 7a63936d4ecddb1048228e778f14ff01fb3b693c | |
| parent | ca03954f007ec4d7a7eabe900b609dc906e5c884 (diff) | |
| download | caxlsx-e859d267e9e4239a8f85253f1e303dc27ece0cb6.tar.gz caxlsx-e859d267e9e4239a8f85253f1e303dc27ece0cb6.zip | |
Fix calculation of worksheet name length
- The previous change caused unnecessary issues
- We approximate that Excel calculates the character length with UTF-16
- Fixes https://github.com/caxlsx/caxlsx/issues/67
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | lib/axlsx/workbook/worksheet/worksheet.rb | 4 | ||||
| -rw-r--r-- | test/workbook/worksheet/tc_worksheet.rb | 45 |
3 files changed, 28 insertions, 22 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index af3432c7..cd16e6e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG - **Unreleased** - [PR #56](https://github.com/caxlsx/caxlsx/pull/56) - Add `zip_command` option to `#serialize` for faster serialization of large Excel files by using a zip binary - [PR #54](https://github.com/caxlsx/caxlsx/pull/54) - Fix type detection for floats with out-of-rage exponents + - [I #67](https://github.com/caxlsx/caxlsx/issues/67) - Fix regression in worksheet name length enforcement: Some unicode characters were counted incorrectly, so that names that previously worked fine now stopped working. (This was introduced in 3.0.2) - **July.16.20**: 3.0.2 - [I #51](https://github.com/caxlsx/caxlsx/issues/51) - Images do not import on Windows. IO read set explicitly to binary mode. diff --git a/lib/axlsx/workbook/worksheet/worksheet.rb b/lib/axlsx/workbook/worksheet/worksheet.rb index aae91947..9f3966f8 100644 --- a/lib/axlsx/workbook/worksheet/worksheet.rb +++ b/lib/axlsx/workbook/worksheet/worksheet.rb @@ -663,7 +663,9 @@ module Axlsx def validate_sheet_name(name) DataTypeValidator.validate :worksheet_name, String, name - raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if name.bytesize > 31 + # ignore first character (BOM) after encoding to utf16 because Excel does so, too. + character_length = name.encode("utf-16")[1..-1].encode("utf-16").bytesize / 2 + raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if character_length > 31 raise ArgumentError, (ERR_SHEET_NAME_CHARACTER_FORBIDDEN % name) if '[]*/\?:'.chars.any? { |char| name.include? char } name = Axlsx::coder.encode(name) sheet_names = @workbook.worksheets.reject { |s| s == self }.map { |s| s.name } diff --git a/test/workbook/worksheet/tc_worksheet.rb b/test/workbook/worksheet/tc_worksheet.rb index 7ef3a3ba..734096b5 100644 --- a/test/workbook/worksheet/tc_worksheet.rb +++ b/test/workbook/worksheet/tc_worksheet.rb @@ -29,6 +29,30 @@ class TestWorksheet < Test::Unit::TestCase assert_raises(ArgumentError) { @ws.name = 'foo?bar' } end + def test_name_unique + assert_raise(ArgumentError, "worksheet name must be unique") { n = @ws.name; @ws.workbook.add_worksheet(:name=> n) } + end + + def test_name_unique_only_checks_other_worksheet_names + assert_nothing_raised { @ws.name = @ws.name } + assert_nothing_raised { Axlsx::Package.new.workbook.add_worksheet :name => 'Sheet1' } + end + + def test_exception_if_name_too_long + assert_nothing_raised { @ws.name = 'x' * 31 } + assert_raises(ArgumentError) { @ws.name = 'x' * 32 } + end + + def test_exception_if_name_too_long_because_of_multibyte_characters + four_characters_for_excel = "\u{1F1EB 1F1F7}" # french flag emoji + assert_raises(ArgumentError, "name too long!") do + @ws.name = four_characters_for_excel + "x" * 28 + end + assert_nothing_raised { @ws.name = "#{four_characters_for_excel}123456789012345678901234567" } + assert_nothing_raised { @ws.name = "123456789012345678901234567890…" } + assert_nothing_raised { @ws.name = "123456789012345678901234567890✔" } + end + def test_page_margins assert(@ws.page_margins.is_a? Axlsx::PageMargins) end @@ -449,27 +473,6 @@ class TestWorksheet < Test::Unit::TestCase assert_equal(@ws.relationships.size, 4, "adding a pivot table adds 1 relationship") end - - def test_name_unique - assert_raise(ArgumentError, "worksheet name must be unique") { n = @ws.name; @ws.workbook.add_worksheet(:name=> n) } - end - - def test_name_unique_only_checks_other_worksheet_names - assert_nothing_raised { @ws.name = @ws.name } - assert_nothing_raised { Axlsx::Package.new.workbook.add_worksheet :name => 'Sheet1' } - end - - def test_exception_if_name_too_long - assert_nothing_raised { @ws.name = 'x' * 31 } - assert_raises(ArgumentError) { @ws.name = 'x' * 32 } - end - - def test_exception_if_name_too_long_because_of_multibyte_characters - three_byte_character = "✔" - assert_nothing_raised { @ws.name = 'x' * 28 + three_byte_character} - assert_raises(ArgumentError) { @ws.name = 'x' * 29 + three_byte_character } - end - def test_set_fixed_width_column @ws.add_row ["mule", "donkey", "horse"], :widths => [20, :ignore, nil] assert(@ws.column_info.size == 3, "a data item for each column") |
