mirror of
https://github.com/apache/thrift.git
synced 2026-10-29 08:55:16 +08:00
Client: cpp Two cases in ToStringTest call std::locale::global() and never put back what was there. Setting it is the point -- they prove to_string() does not follow the global locale, which is why TToString.h imbues a default one on the streams it builds -- but leaving it set is not. Every stream constructed later in the same UnitTests binary picks it up, in suites that have nothing to do with this one, and numbers formatted through an ostringstream come out with digit grouping. That has already cost a debugging session. A case in THttpBufferBoundTest formats a chunk size with "size << std::hex << 4096" and got "1.000" rather than "1000", so the transport under test read a different stream, and the case passed or failed depending on whether it ran alone or in a full run -- ToStringTest is disabled by default and only runs when the whole binary does. A scoped guard restores the previous global locale on exit. The cases still set the locale for their own duration, so what they assert is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
193 lines
5.6 KiB
C++
193 lines
5.6 KiB
C++
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <locale>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
#include <thrift/TToString.h>
|
|
|
|
#include "gen-cpp/ThriftTest_types.h"
|
|
#include "gen-cpp/OptionalRequiredTest_types.h"
|
|
#include "gen-cpp/DebugProtoTest_types.h"
|
|
|
|
using apache::thrift::to_string;
|
|
|
|
BOOST_AUTO_TEST_SUITE(ToStringTest)
|
|
|
|
namespace {
|
|
|
|
// The two cases below set the global locale to prove that to_string() does not
|
|
// follow it. Setting it is the point; leaving it set is not -- every stream
|
|
// constructed later in this binary picks it up, including in suites that have
|
|
// nothing to do with this one, and a number then formats with digit grouping.
|
|
// That has already cost one debugging session in THttpBufferBoundTest, where a
|
|
// hex chunk size of 4096 became "1.000".
|
|
class ScopedGlobalLocale {
|
|
public:
|
|
explicit ScopedGlobalLocale(const char* name)
|
|
: previous_(std::locale::global(std::locale(name))) {}
|
|
~ScopedGlobalLocale() { std::locale::global(previous_); }
|
|
|
|
private:
|
|
std::locale previous_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
BOOST_AUTO_TEST_CASE(base_types_to_string) {
|
|
BOOST_CHECK_EQUAL(to_string(10), "10");
|
|
BOOST_CHECK_EQUAL(to_string(true), "1");
|
|
BOOST_CHECK_EQUAL(to_string('a'), "a");
|
|
BOOST_CHECK_EQUAL(to_string(1.2), "1.2");
|
|
BOOST_CHECK_EQUAL(to_string("abc"), "abc");
|
|
}
|
|
|
|
// NOTE: Currently (as of 2021.08.12) the locale-based tests do not work on
|
|
// Windows in the AppVeyor Thrift CI build correctly. Therefore disabled on
|
|
// Windows:
|
|
#ifndef _WIN32
|
|
BOOST_AUTO_TEST_CASE(locale_en_US_int_to_string) {
|
|
#ifdef _WIN32
|
|
ScopedGlobalLocale locale("en-US.UTF-8");
|
|
#else
|
|
ScopedGlobalLocale locale("en_US.UTF-8");
|
|
#endif
|
|
BOOST_CHECK_EQUAL(to_string(1000000), "1000000");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(locale_de_DE_floating_point_to_string) {
|
|
#ifdef _WIN32
|
|
ScopedGlobalLocale locale("de-DE.UTF-8");
|
|
#else
|
|
ScopedGlobalLocale locale("de_DE.UTF-8");
|
|
#endif
|
|
BOOST_CHECK_EQUAL(to_string(1.5), "1.5");
|
|
BOOST_CHECK_EQUAL(to_string(1.5f), "1.5");
|
|
BOOST_CHECK_EQUAL(to_string(1.5L), "1.5");
|
|
}
|
|
#endif
|
|
|
|
BOOST_AUTO_TEST_CASE(empty_vector_to_string) {
|
|
std::vector<int> l;
|
|
BOOST_CHECK_EQUAL(to_string(l), "[]");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(single_item_vector_to_string) {
|
|
std::vector<int> l;
|
|
l.push_back(100);
|
|
BOOST_CHECK_EQUAL(to_string(l), "[100]");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(multiple_item_vector_to_string) {
|
|
std::vector<int> l;
|
|
l.push_back(100);
|
|
l.push_back(150);
|
|
BOOST_CHECK_EQUAL(to_string(l), "[100, 150]");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(empty_map_to_string) {
|
|
std::map<int, std::string> m;
|
|
BOOST_CHECK_EQUAL(to_string(m), "{}");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(single_item_map_to_string) {
|
|
std::map<int, std::string> m;
|
|
m[12] = "abc";
|
|
BOOST_CHECK_EQUAL(to_string(m), "{12: abc}");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(multi_item_map_to_string) {
|
|
std::map<int, std::string> m;
|
|
m[12] = "abc";
|
|
m[31] = "xyz";
|
|
BOOST_CHECK_EQUAL(to_string(m), "{12: abc, 31: xyz}");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(empty_set_to_string) {
|
|
std::set<char> s;
|
|
BOOST_CHECK_EQUAL(to_string(s), "{}");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(single_item_set_to_string) {
|
|
std::set<char> s;
|
|
s.insert('c');
|
|
BOOST_CHECK_EQUAL(to_string(s), "{c}");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(multi_item_set_to_string) {
|
|
std::set<char> s;
|
|
s.insert('a');
|
|
s.insert('z');
|
|
BOOST_CHECK_EQUAL(to_string(s), "{a, z}");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(generated_empty_object_to_string) {
|
|
thrift::test::EmptyStruct e;
|
|
BOOST_CHECK_EQUAL(to_string(e), "EmptyStruct()");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(generated_single_basic_field_object_to_string) {
|
|
thrift::test::StructA a;
|
|
a.__set_s("abcd");
|
|
BOOST_CHECK_EQUAL(to_string(a), "StructA(s=abcd)");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(generated_two_basic_fields_object_to_string) {
|
|
thrift::test::Bonk a;
|
|
a.__set_message("abcd");
|
|
a.__set_type(1234);
|
|
BOOST_CHECK_EQUAL(to_string(a), "Bonk(message=abcd, type=1234)");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(generated_optional_fields_object_to_string) {
|
|
thrift::test::Tricky2 a;
|
|
BOOST_CHECK_EQUAL(to_string(a), "Tricky2(im_optional=<null>)");
|
|
a.__set_im_optional(123);
|
|
BOOST_CHECK_EQUAL(to_string(a), "Tricky2(im_optional=123)");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(generated_nested_object_to_string) {
|
|
thrift::test::OneField a;
|
|
BOOST_CHECK_EQUAL(to_string(a), "OneField(field=EmptyStruct())");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(generated_nested_list_object_to_string) {
|
|
thrift::test::ListBonks l;
|
|
l.bonk.assign(2, thrift::test::Bonk());
|
|
l.bonk[0].__set_message("a");
|
|
l.bonk[1].__set_message("b");
|
|
|
|
BOOST_CHECK_EQUAL(to_string(l),
|
|
"ListBonks(bonk=[Bonk(message=a, type=0), Bonk(message=b, type=0)])");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(generated_uuid_to_string) {
|
|
thrift::test::CrazyNesting l;
|
|
l.uuid_field = apache::thrift::TUuid{"{4b686716-5f20-4deb-8ce0-9eaf379e8a3d}"};
|
|
|
|
BOOST_CHECK_EQUAL(to_string(l),
|
|
"CrazyNesting(string_field=, set_field=<null>, list_field=[], binary_field=, "
|
|
"uuid_field=4b686716-5f20-4deb-8ce0-9eaf379e8a3d)");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|