Commit 39cadacc authored by Yoshi Cheng-Hao Huang's avatar Yoshi Cheng-Hao Huang
Browse files

Bug 1719747 - Part 1: Unify ListFormat in SM. r=gregtatum,anba,platform-i18n-reviewers,tcampbell

Move implementations to mozilla::intl::ListFormat

Differential Revision: https://phabricator.services.mozilla.com/D122334
parent 945a8b69
Loading
Loading
Loading
Loading
+140 −0
Original line number Diff line number Diff line
/* 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 "gtest/gtest.h"

#include "mozilla/intl/ListFormat.h"
#include "mozilla/Span.h"
#include "TestBuffer.h"

namespace mozilla::intl {

// Test ListFormat.format with default options.
TEST(IntlListFormat, FormatDefault)
{
  ListFormat::Options options;
  UniquePtr<ListFormat> lf = ListFormat::TryCreate("en-US", options).unwrap();
  ListFormat::StringList list;
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Alice")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Bob")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Charlie")));
  TestBuffer<char16_t> buf16;
  ASSERT_TRUE(lf->Format(list, buf16).isOk());
  ASSERT_EQ(buf16.get_string_view(), u"Alice, Bob, and Charlie");

  UniquePtr<ListFormat> lfDe = ListFormat::TryCreate("de", options).unwrap();
  ASSERT_TRUE(lfDe->Format(list, buf16).isOk());
  ASSERT_EQ(buf16.get_string_view(), u"Alice, Bob und Charlie");
}

// Test ListFormat.format with Type::Conjunction and other styles.
TEST(IntlListFormat, FormatConjunction)
{
  ListFormat::Options options{ListFormat::Type::Conjunction,
                              ListFormat::Style::Narrow};
  UniquePtr<ListFormat> lf = ListFormat::TryCreate("en-US", options).unwrap();
  ListFormat::StringList list;
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Alice")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Bob")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Charlie")));
  TestBuffer<char16_t> buf16;
  ASSERT_TRUE(lf->Format(list, buf16).isOk());
  ASSERT_EQ(buf16.get_string_view(), u"Alice, Bob, Charlie");

  ListFormat::Options optionsSh{ListFormat::Type::Conjunction,
                                ListFormat::Style::Short};
  UniquePtr<ListFormat> lfSh =
      ListFormat::TryCreate("en-US", optionsSh).unwrap();
  ASSERT_TRUE(lfSh->Format(list, buf16).isOk());
  ASSERT_EQ(buf16.get_string_view(), u"Alice, Bob, & Charlie");
}

// Test ListFormat.format with Type::Disjunction.
TEST(IntlListFormat, FormatDisjunction)
{
  // When Type is Disjunction, the results will be the same regardless of the
  // style for most locales, so simply test with Style::Long.
  ListFormat::Options options{ListFormat::Type::Disjunction,
                              ListFormat::Style::Long};
  UniquePtr<ListFormat> lf = ListFormat::TryCreate("en-US", options).unwrap();
  ListFormat::StringList list;
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Alice")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Bob")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Charlie")));
  TestBuffer<char16_t> buf16;
  ASSERT_TRUE(lf->Format(list, buf16).isOk());
  ASSERT_EQ(buf16.get_string_view(), u"Alice, Bob, or Charlie");
}

// Test ListFormat.format with Type::Unit.
TEST(IntlListFormat, FormatUnit)
{
  ListFormat::Options options{ListFormat::Type::Unit, ListFormat::Style::Long};
  // For locale "en", Style::Long and Style::Short have the same result, so just
  // test Style::Long here.
  UniquePtr<ListFormat> lf = ListFormat::TryCreate("en-US", options).unwrap();
  ListFormat::StringList list;
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Alice")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Bob")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Charlie")));
  TestBuffer<char16_t> buf16;
  ASSERT_TRUE(lf->Format(list, buf16).isOk());
  ASSERT_EQ(buf16.get_string_view(), u"Alice, Bob, Charlie");

  ListFormat::Options optionsNa{ListFormat::Type::Unit,
                                ListFormat::Style::Narrow};
  UniquePtr<ListFormat> lfNa =
      ListFormat::TryCreate("en-US", optionsNa).unwrap();
  ASSERT_TRUE(lfNa->Format(list, buf16).isOk());
  ASSERT_EQ(buf16.get_string_view(), u"Alice Bob Charlie");
}

// Pass a long list (list.length() > DEFAULT_LIST_LENGTH) and check the result
// is still correct. (result.length > INITIAL_CHAR_BUFFER_SIZE)
TEST(IntlListFormat, FormatBufferLength)
{
  ListFormat::Options options;
  UniquePtr<ListFormat> lf = ListFormat::TryCreate("en-US", options).unwrap();
  ListFormat::StringList list;
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Alice")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Bob")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Charlie")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"David")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Eve")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Frank")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Grace")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Heidi")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Ivan")));
  TestBuffer<char16_t> buf16;
  ASSERT_TRUE(lf->Format(list, buf16).isOk());
  ASSERT_EQ(buf16.get_string_view(),
            u"Alice, Bob, Charlie, David, Eve, Frank, Grace, Heidi, and Ivan");
}

TEST(IntlListFormat, FormatToParts)
{
  ListFormat::Options options;
  UniquePtr<ListFormat> lf = ListFormat::TryCreate("en-US", options).unwrap();
  ListFormat::StringList list;
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Alice")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Bob")));
  MOZ_RELEASE_ASSERT(list.append(MakeStringSpan(u"Charlie")));
  ListFormat::PartVector parts;
  ASSERT_TRUE(lf->FormatToParts(list, parts).isOk());

  // 3 elements, and 2 literals.
  ASSERT_EQ(parts.length(), 5u);

  ASSERT_EQ(parts[0], (ListFormat::Part{ListFormat::PartType::Element,
                                        MakeStringSpan(u"Alice")}));
  ASSERT_EQ(parts[1], (ListFormat::Part{ListFormat::PartType::Literal,
                                        MakeStringSpan(u", ")}));
  ASSERT_EQ(parts[2], (ListFormat::Part{ListFormat::PartType::Element,
                                        MakeStringSpan(u"Bob")}));
  ASSERT_EQ(parts[3], (ListFormat::Part{ListFormat::PartType::Literal,
                                        MakeStringSpan(u", and ")}));
  ASSERT_EQ(parts[4], (ListFormat::Part{ListFormat::PartType::Element,
                                        MakeStringSpan(u"Charlie")}));
}

}  // namespace mozilla::intl
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ UNIFIED_SOURCES += [
    "TestCalendar.cpp",
    "TestCollator.cpp",
    "TestDateTimeFormat.cpp",
    "TestListFormat.cpp",
    "TestLocaleCanonicalizer.cpp",
    "TestNumberFormat.cpp",
    "TestPluralRules.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ EXPORTS.mozilla.intl = [
    "src/DateTimePatternGenerator.h",
    "src/ICU4CGlue.h",
    "src/ICUError.h",
    "src/ListFormat.h",
    "src/LocaleCanonicalizer.h",
    "src/NumberFormat.h",
    "src/NumberFormatFields.h",
@@ -24,6 +25,7 @@ UNIFIED_SOURCES += [
    "src/DateTimeFormat.cpp",
    "src/DateTimePatternGenerator.cpp",
    "src/ICU4CGlue.cpp",
    "src/ListFormat.cpp",
    "src/LocaleCanonicalizer.cpp",
    "src/NumberFormat.cpp",
    "src/NumberFormatFields.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ class ICUPointer {
  const T* GetConst() const { return const_cast<const T*>(mPointer); }
  T* GetMut() { return mPointer; }

  explicit operator bool() const { return !!mPointer; }

 private:
  T* mPointer;
};
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ namespace mozilla::intl {
enum class ICUError : uint8_t {
  OutOfMemory,
  InternalError,
  OverflowError,
};

/**
Loading