Files
odfstudio/i18nutil/qa/cppunit/test_unicodeescape.cxx
T
AnamayNarkar 5936fab3e6 tdf#106137 i18nutil: Add helper to process Unicode escapes
Adds a new utility function processUnicodeEscapes() to i18nutil.
This supports parsing:
* Standard escapes: \uhhhh (e.g. \u0041)
* Extended escapes: \Uhhhhhhhh (e.g. \U0001F600)
* Escaped backslashes: \\

Change-Id: I589eb2403376c8cef694f52f1c785d42fba94ff9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198777
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
2026-03-03 07:19:32 +01:00

122 lines
3.7 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/plugin/TestPlugIn.h>
#include <i18nutil/unicodeescape.hxx>
#include <o3tl/string_view.hxx>
using namespace o3tl;
class TestUnicodeEscape : public CppUnit::TestFixture
{
public:
void testBasicUnicodeEscape();
void testExtendedUnicodeEscape();
void testEscapedBackslash();
void testInvalidEscape();
void testControlCharFiltering();
void testSurrogatePair();
CPPUNIT_TEST_SUITE(TestUnicodeEscape);
CPPUNIT_TEST(testBasicUnicodeEscape);
CPPUNIT_TEST(testExtendedUnicodeEscape);
CPPUNIT_TEST(testEscapedBackslash);
CPPUNIT_TEST(testInvalidEscape);
CPPUNIT_TEST(testControlCharFiltering);
CPPUNIT_TEST(testSurrogatePair);
CPPUNIT_TEST_SUITE_END();
};
void TestUnicodeEscape::testBasicUnicodeEscape()
{
// \u0041 should become 'A'
OUString input(u"\\u0041"_ustr);
OUString result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(u"A"_ustr, result);
// Multiple escapes
input = u"\\u0041\\u0042\\u0043"_ustr;
result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(u"ABC"_ustr, result);
// Mixed with text
input = u"Hello \\u0041 World"_ustr;
result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(u"Hello A World"_ustr, result);
}
void TestUnicodeEscape::testExtendedUnicodeEscape()
{
// \U00000041 should become 'A'
OUString result = i18nutil::processUnicodeEscapes(u"\\U00000041");
CPPUNIT_ASSERT_EQUAL(u"A"_ustr, result);
}
void TestUnicodeEscape::testEscapedBackslash()
{
// \\u0041 should become literal \u0041
OUString result = i18nutil::processUnicodeEscapes(u"\\\\u0041");
CPPUNIT_ASSERT_EQUAL(u"\\u0041"_ustr, result);
}
void TestUnicodeEscape::testInvalidEscape()
{
// Invalid hex should keep literal
OUString input(u"\\uXYZW"_ustr);
OUString result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(input, result);
// Incomplete escape should keep literal
input = u"\\u004"_ustr;
result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(input, result);
}
void TestUnicodeEscape::testControlCharFiltering()
{
// \u000A (LF) should be allowed
OUString input(u"\\u000A"_ustr);
OUString result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(u"\n"_ustr, result);
// \u0009 (TAB) should be allowed
input = u"\\u0009"_ustr;
result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(u"\t"_ustr, result);
// \u0000 (NULL) should be filtered
input = u"\\u0000"_ustr;
result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(input, result); // Should remain literal
input = u"\\\\uXYZW"_ustr;
result = i18nutil::processUnicodeEscapes(input);
CPPUNIT_ASSERT_EQUAL(u"\\uXYZW"_ustr, result);
}
void TestUnicodeEscape::testSurrogatePair()
{
// \U0001F600 (emoji) should work with surrogate pairs
OUString result = i18nutil::processUnicodeEscapes(u"\\U0001F600");
// U+1F600 = UTF-16: 0xD83D 0xDE00
sal_Unicode surrogates[2] = { 0xD83D, 0xDE00 };
OUString expected(surrogates, 2);
CPPUNIT_ASSERT_EQUAL(expected, result);
}
CPPUNIT_TEST_SUITE_REGISTRATION(TestUnicodeEscape);
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */