From 0e22868ffe93acf4cc4dba933225a0812c0aa6ec Mon Sep 17 00:00:00 2001 From: Lieven De Foor Date: Wed, 6 May 2026 14:30:25 +0200 Subject: [PATCH] Fix: Honor CompareOptions and Culture in RangeSortOptions Fixed a bug where the internal string comparer in EPPlus sorting hard-coded StringComparison.CurrentCulture, effectively ignoring the CompareOptions (like Ordinal or IgnoreCase) provided by the user. - Updated EPPlusSortComparerBase to use Culture and CompOptions properties. - Added unit tests to verify linguistic and ordinal case-sensitivity. --- .../Internal/EPPlusSortComparerBase.cs | 2 +- .../Sorting/SortCaseSensitivityTests.cs | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/EPPlusTest/Sorting/SortCaseSensitivityTests.cs diff --git a/src/EPPlus/Sorting/Internal/EPPlusSortComparerBase.cs b/src/EPPlus/Sorting/Internal/EPPlusSortComparerBase.cs index 018975bf61..1730e83b52 100644 --- a/src/EPPlus/Sorting/Internal/EPPlusSortComparerBase.cs +++ b/src/EPPlus/Sorting/Internal/EPPlusSortComparerBase.cs @@ -76,7 +76,7 @@ protected int CompareObjects(object x1, object y1) { var s1 = x1 == null ? "" : x1.ToString(); var s2 = y1 == null ? "" : y1.ToString(); - ret = string.Compare(s1, s2, StringComparison.CurrentCulture); + ret = string.Compare(s1, s2, Culture ?? CultureInfo.CurrentCulture, CompOptions); } else { diff --git a/src/EPPlusTest/Sorting/SortCaseSensitivityTests.cs b/src/EPPlusTest/Sorting/SortCaseSensitivityTests.cs new file mode 100644 index 0000000000..cc8c2f1f13 --- /dev/null +++ b/src/EPPlusTest/Sorting/SortCaseSensitivityTests.cs @@ -0,0 +1,67 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OfficeOpenXml; +using OfficeOpenXml.Sorting; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace EPPlusTest.Sorting +{ + [TestClass] + public class SortCaseSensitivityTests : TestBase + { + [TestMethod] + public void ShouldRespectCaseSensitivity() + { + using (var package = new ExcelPackage()) + { + var sheet = package.Workbook.Worksheets.Add("SortTest"); + + // Data: APPLE then apple + sheet.Cells["A1"].Value = "APPLE"; + sheet.Cells["A2"].Value = "apple"; + + // 1. Case-Insensitive Sort (Should preserve original order APPLE, apple) + var options = RangeSortOptions.Create(); + options.CompareOptions = CompareOptions.IgnoreCase; + options.SortBy.Column(0); + sheet.Cells["A1:A2"].Sort(options); + + Assert.AreEqual("APPLE", sheet.Cells["A1"].Text, "Insensitive sort failed to preserve order"); + Assert.AreEqual("apple", sheet.Cells["A2"].Text); + + // 2. Case-Sensitive Sort (Should flip to apple, APPLE because a < A in linguistic sort) + options = RangeSortOptions.Create(); + options.CompareOptions = CompareOptions.None; // linguistic sensitive + options.SortBy.Column(0); + sheet.Cells["A1:A2"].Sort(options); + + Assert.AreEqual("apple", sheet.Cells["A1"].Text, "Sensitive sort failed to flip order"); + Assert.AreEqual("APPLE", sheet.Cells["A2"].Text); + } + } + + [TestMethod] + public void ShouldRespectOrdinalCaseSensitivity() + { + using (var package = new ExcelPackage()) + { + var sheet = package.Workbook.Worksheets.Add("SortTestOrdinal"); + + // Data: apple then APPLE + sheet.Cells["A1"].Value = "apple"; + sheet.Cells["A2"].Value = "APPLE"; + + // Ordinal Sort (Binary): A (65) < a (97). So APPLE should be first. + var options = RangeSortOptions.Create(); + options.CompareOptions = CompareOptions.Ordinal; + options.SortBy.Column(0); + sheet.Cells["A1:A2"].Sort(options); + + Assert.AreEqual("APPLE", sheet.Cells["A1"].Text, "Ordinal sort failed to put uppercase first"); + Assert.AreEqual("apple", sheet.Cells["A2"].Text); + } + } + } +}