diff --git a/xbmc/utils/Locale.cpp b/xbmc/utils/Locale.cpp new file mode 100644 index 0000000000000..a8cfefa94d284 --- /dev/null +++ b/xbmc/utils/Locale.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2015 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "Locale.h" +#include "utils/StringUtils.h" + +const CLocale CLocale::Empty; + +CLocale::CLocale() + : m_valid(false), + m_language(), + m_territory(), + m_codeset(), + m_modifier() +{ } + +CLocale::CLocale(const std::string& language) + : m_valid(false), + m_language(), + m_territory(), + m_codeset(), + m_modifier() +{ + m_valid = ParseLocale(language, m_language, m_territory, m_codeset, m_modifier); +} + +CLocale::CLocale(const std::string& language, const std::string& territory) + : m_valid(false), + m_language(language), + m_territory(territory), + m_codeset(), + m_modifier() +{ + Initialize(); +} + +CLocale::CLocale(const std::string& language, const std::string& territory, const std::string& codeset) + : m_valid(false), + m_language(language), + m_territory(territory), + m_codeset(codeset), + m_modifier() +{ + Initialize(); +} + +CLocale::CLocale(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier) + : m_valid(false), + m_language(language), + m_territory(territory), + m_codeset(codeset), + m_modifier(modifier) +{ + Initialize(); +} + +CLocale::~CLocale() +{ } + +CLocale CLocale::FromString(const std::string& locale) +{ + return CLocale(locale); +} + +bool CLocale::operator==(const CLocale& other) const +{ + if (!m_valid && !other.m_valid) + return true; + + return m_valid == other.m_valid && + StringUtils::EqualsNoCase(m_language, other.m_language) && + StringUtils::EqualsNoCase(m_territory, other.m_territory) && + StringUtils::EqualsNoCase(m_codeset, other.m_codeset) && + StringUtils::EqualsNoCase(m_modifier, other.m_modifier); +} + +std::string CLocale::ToString() const +{ + if (!m_valid) + return ""; + + std::string locale = ToShortString(); + + if (!m_codeset.empty()) + locale += "." + m_codeset; + + if (!m_modifier.empty()) + locale += "@" + m_modifier; + + return locale; +} + +std::string CLocale::ToStringLC() const +{ + if (!m_valid) + return ""; + + std::string locale = ToString(); + StringUtils::ToLower(locale); + + return locale; +} + +std::string CLocale::ToShortString() const +{ + if (!m_valid) + return ""; + + std::string locale = m_language; + + if (!m_territory.empty()) + locale += "_" + m_territory; + + return locale; +} + +std::string CLocale::ToShortStringLC() const +{ + if (!m_valid) + return ""; + + std::string locale = ToShortString(); + StringUtils::ToLower(locale); + + return locale; +} + +bool CLocale::Equals(const std::string& locale) const +{ + CLocale other = FromString(locale); + + return *this == other; +} + +bool CLocale::Matches(const std::string& locale) const +{ + CLocale other = FromString(locale); + + if (!m_valid && !other.m_valid) + return true; + if (!m_valid || !other.m_valid) + return false; + + if (!StringUtils::EqualsNoCase(m_language, other.m_language)) + return false; + if (!m_territory.empty() && !other.m_territory.empty() && !StringUtils::EqualsNoCase(m_territory, other.m_territory)) + return false; + if (!m_codeset.empty() && !other.m_codeset.empty() && !StringUtils::EqualsNoCase(m_codeset, other.m_codeset)) + return false; + if (!m_modifier.empty() && !other.m_modifier.empty() && !StringUtils::EqualsNoCase(m_modifier, other.m_modifier)) + return false; + + return true; +} + +bool CLocale::CheckValidity(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier) +{ + static_cast(territory); + static_cast(codeset); + static_cast(modifier); + + return !language.empty(); +} + +bool CLocale::ParseLocale(const std::string &locale, std::string &language, std::string &territory, std::string &codeset, std::string &modifier) +{ + if (locale.empty()) + return false; + + language.clear(); + territory.clear(); + codeset.clear(); + modifier.clear(); + + // the format for a locale is [language[_territory][.codeset][@modifier]] + std::string tmp = locale; + + // look for the modifier after @ + size_t pos = tmp.find("@"); + if (pos != std::string::npos) + { + modifier = tmp.substr(pos + 1); + tmp = tmp.substr(0, pos); + } + + // look for the codeset after . + pos = tmp.find("."); + if (pos != std::string::npos) + { + codeset = tmp.substr(pos + 1); + tmp = tmp.substr(0, pos); + } + + // look for the codeset after _ + pos = tmp.find("_"); + if (pos != std::string::npos) + { + territory = tmp.substr(pos + 1); + StringUtils::ToUpper(territory); + tmp = tmp.substr(0, pos); + } + + // what remains is the language + language = tmp; + StringUtils::ToLower(language); + + return CheckValidity(language, territory, codeset, modifier); +} + +void CLocale::Initialize() +{ + m_valid = CheckValidity(m_language, m_territory, m_codeset, m_modifier); + if (m_valid) + { + StringUtils::ToLower(m_language); + StringUtils::ToUpper(m_territory); + } +} diff --git a/xbmc/utils/Locale.h b/xbmc/utils/Locale.h new file mode 100644 index 0000000000000..b49cfaa6b115b --- /dev/null +++ b/xbmc/utils/Locale.h @@ -0,0 +1,146 @@ +#pragma once +/* + * Copyright (C) 2015 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include + +/*! + \brief Class representing a full locale of the form [language[_territory][.codeset][@modifier]]. + */ +class CLocale +{ +public: + CLocale(); + CLocale(const std::string& language); + CLocale(const std::string& language, const std::string& territory); + CLocale(const std::string& language, const std::string& territory, const std::string& codeset); + CLocale(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier); + ~CLocale(); + + /*! + \brief Empty (and invalid) CLocale instance. + */ + static const CLocale Empty; + + /*! + \brief Parses the given string representation and turns it into a locale. + + \param locale String representation of a locale + */ + static CLocale FromString(const std::string& locale); + + bool operator==(const CLocale& other) const; + inline bool operator!=(const CLocale& other) const { return !(*this == other); } + + /*! + \brief Whether the locale is valid or not. + + \details A locale is considered valid if at least the language code is set. + */ + bool IsValid() const { return m_valid; } + + /*! + \brief Returns the (lower-case) ISO 639-1 language code of the locale. + */ + const std::string& GetLanguageCode() const { return m_language; } + /*! + \brief Returns the (upper-case) ISO 3166-1 Alpha-2 territory code of the locale. + */ + const std::string& GetTerritoryCode() const { return m_territory; } + /*! + \brief Returns the codeset of the locale. + */ + const std::string& GetCodeset() const { return m_codeset; } + /*! + \brief Returns the modifier of the locale. + */ + const std::string& GetModifier() const { return m_modifier; } + + /*! + \brief Returns the full string representation of the locale. + + \details The format of the string representation is + [language[_territory][.codeset][@modifier]] where the language is + represented as a (lower-case) two character ISO 639-1 code and the territory + is represented as a (upper-case) two character ISO 3166-1 Alpha-2 code. + */ + std::string ToString() const; + /*! + \brief Returns the full string representation of the locale in lowercase. + + \details The format of the string representation is + [language[_territory][.codeset][@modifier]] where the language is + represented as a two character ISO 639-1 code and the territory is + represented as a two character ISO 3166-1 Alpha-2 code. + */ + std::string ToStringLC() const; + /*! + \brief Returns the short string representation of the locale. + + \details The format of the short string representation is + [language[_territory] where the language is represented as a (lower-case) + two character ISO 639-1 code and the territory is represented as a + (upper-case) two character ISO 3166-1 Alpha-2 code. + */ + std::string ToShortString() const; + /*! + \brief Returns the short string representation of the locale in lowercase. + + \details The format of the short string representation is + [language[_territory] where the language is represented as a two character + ISO 639-1 code and the territory is represented as a two character + ISO 3166-1 Alpha-2 code. + */ + std::string ToShortStringLC() const; + + /*! + \brief Checks if the given string representation of a locale exactly matches + the locale. + + \param locale String representation of a locale + \return True if the string representation matches the locale, false otherwise. + */ + bool Equals(const std::string& locale) const; + + /*! + \brief Checks if the given string representation of a locale partly matches + the locale. + + \details Partial matching means that every available locale part needs to + match the same locale part of the other locale if present. + + \param locale String representation of a locale + \return True if the string representation matches the locale, false otherwise. + */ + bool Matches(const std::string& locale) const; + +private: + static bool CheckValidity(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier); + static bool ParseLocale(const std::string &locale, std::string &language, std::string &territory, std::string &codeset, std::string &modifier); + + void Initialize(); + + bool m_valid; + std::string m_language; + std::string m_territory; + std::string m_codeset; + std::string m_modifier; +}; + diff --git a/xbmc/utils/Makefile.in b/xbmc/utils/Makefile.in index 53e72084afb1d..abe863f8aeab4 100644 --- a/xbmc/utils/Makefile.in +++ b/xbmc/utils/Makefile.in @@ -39,6 +39,7 @@ SRCS += JSONVariantWriter.cpp SRCS += LabelFormatter.cpp SRCS += LangCodeExpander.cpp SRCS += LegacyPathTranslation.cpp +SRCS += Locale.cpp SRCS += log.cpp SRCS += md5.cpp SRCS += Mime.cpp diff --git a/xbmc/utils/test/Makefile b/xbmc/utils/test/Makefile index aa84d3e386aa0..282f6eb88cf17 100644 --- a/xbmc/utils/test/Makefile +++ b/xbmc/utils/test/Makefile @@ -28,6 +28,7 @@ SRCS= \ TestJSONVariantWriter.cpp \ TestLabelFormatter.cpp \ TestLangCodeExpander.cpp \ + TestLocale.cpp \ Testlog.cpp \ TestMathUtils.cpp \ Testmd5.cpp \ diff --git a/xbmc/utils/test/TestLocale.cpp b/xbmc/utils/test/TestLocale.cpp new file mode 100644 index 0000000000000..e54477b6d588b --- /dev/null +++ b/xbmc/utils/test/TestLocale.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2015 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include + +#include "utils/Locale.h" +#include "utils/StringUtils.h" + +static const std::string TerritorySeparator = "_"; +static const std::string CodesetSeparator = "."; +static const std::string ModifierSeparator = "@"; + +static const std::string LanguageCodeEnglish = "en"; +static const std::string TerritoryCodeBritain = "GB"; +static const std::string CodesetUtf8 = "UTF-8"; +static const std::string ModifierLatin = "latin"; + +TEST(TestLocale, DefaultLocale) +{ + CLocale locale; + ASSERT_FALSE(locale.IsValid()); + ASSERT_STREQ("", locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ("", locale.ToString().c_str()); +} + +TEST(TestLocale, LanguageLocale) +{ + CLocale locale(LanguageCodeEnglish); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryLocale) +{ + const std::string strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageCodesetLocale) +{ + const std::string strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, "", CodesetUtf8); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageModifierLocale) +{ + const std::string strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, "", "", ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryCodesetLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryModifierLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, "", ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryCodesetModifierLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8, ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, FullStringLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, FromString) +{ + std::string strLocale = ""; + CLocale locale = CLocale::FromString(strLocale); + ASSERT_FALSE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); +} + +TEST(TestLocale, EmptyLocale) +{ + ASSERT_FALSE(CLocale::Empty.IsValid()); + ASSERT_STREQ("", CLocale::Empty.GetLanguageCode().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetTerritoryCode().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetCodeset().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetModifier().c_str()); + ASSERT_STREQ("", CLocale::Empty.ToString().c_str()); +} + +TEST(TestLocale, Equals) +{ + std::string strLocale = ""; + CLocale locale; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish); + strLocale = LanguageCodeEnglish; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, "", CodesetUtf8); + strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, "", "", ModifierLatin); + strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, "", ModifierLatin); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8, ModifierLatin); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); +}