1 | // Copyright Vladimir Prus 2002-2004. |
2 | // Distributed under the Boost Software License, Version 1.0. |
3 | // (See accompanying file LICENSE_1_0.txt |
4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) |
5 | |
6 | |
7 | #include <boost/program_options/variables_map.hpp> |
8 | #include <boost/program_options/options_description.hpp> |
9 | #include <boost/program_options/parsers.hpp> |
10 | #include <boost/program_options/detail/utf8_codecvt_facet.hpp> |
11 | using namespace boost::program_options; |
12 | // We'll use po::value everywhere to workaround vc6 bug. |
13 | namespace po = boost::program_options; |
14 | |
15 | #include <boost/function.hpp> |
16 | using namespace boost; |
17 | |
18 | #include <sstream> |
19 | using namespace std; |
20 | |
21 | #include "minitest.hpp" |
22 | |
23 | // Test that unicode input is forwarded to unicode option without |
24 | // problems. |
25 | void test_unicode_to_unicode() |
26 | { |
27 | options_description desc; |
28 | |
29 | desc.add_options() |
30 | ("foo" , po::wvalue<wstring>(), "unicode option" ) |
31 | ; |
32 | |
33 | vector<wstring> args; |
34 | args.push_back(x: L"--foo=\x044F" ); |
35 | |
36 | variables_map vm; |
37 | basic_parsed_options<wchar_t> parsed = |
38 | wcommand_line_parser(args).options(desc).run(); |
39 | store(options: parsed, m&: vm); |
40 | |
41 | BOOST_CHECK(vm["foo" ].as<wstring>() == L"\x044F" ); |
42 | BOOST_CHECK(parsed.options[0].original_tokens.size() == 1); |
43 | BOOST_CHECK(parsed.options[0].original_tokens[0] == L"--foo=\x044F" ); |
44 | } |
45 | |
46 | // Test that unicode input is property converted into |
47 | // local 8 bit string. To test this, make local 8 bit encoding |
48 | // be utf8. |
49 | void test_unicode_to_native() |
50 | { |
51 | std::codecvt<wchar_t, char, mbstate_t>* facet = |
52 | new boost::program_options::detail::utf8_codecvt_facet; |
53 | locale::global(loc: locale(locale(), facet)); |
54 | |
55 | options_description desc; |
56 | |
57 | desc.add_options() |
58 | ("foo" , po::value<string>(), "unicode option" ) |
59 | ; |
60 | |
61 | vector<wstring> args; |
62 | args.push_back(x: L"--foo=\x044F" ); |
63 | |
64 | variables_map vm; |
65 | store(options: wcommand_line_parser(args).options(desc).run(), m&: vm); |
66 | |
67 | BOOST_CHECK(vm["foo" ].as<string>() == "\xD1\x8F" ); |
68 | } |
69 | |
70 | void test_native_to_unicode() |
71 | { |
72 | std::codecvt<wchar_t, char, mbstate_t>* facet = |
73 | new boost::program_options::detail::utf8_codecvt_facet; |
74 | locale::global(loc: locale(locale(), facet)); |
75 | |
76 | options_description desc; |
77 | |
78 | desc.add_options() |
79 | ("foo" , po::wvalue<wstring>(), "unicode option" ) |
80 | ; |
81 | |
82 | vector<string> args; |
83 | args.push_back(x: "--foo=\xD1\x8F" ); |
84 | |
85 | variables_map vm; |
86 | store(options: command_line_parser(args).options(desc).run(), m&: vm); |
87 | |
88 | BOOST_CHECK(vm["foo" ].as<wstring>() == L"\x044F" ); |
89 | } |
90 | |
91 | vector<wstring> sv(const wchar_t* array[], unsigned size) |
92 | { |
93 | vector<wstring> r; |
94 | for (unsigned i = 0; i < size; ++i) |
95 | r.push_back(x: array[i]); |
96 | return r; |
97 | } |
98 | |
99 | void check_value(const woption& option, const char* name, const wchar_t* value) |
100 | { |
101 | BOOST_CHECK(option.string_key == name); |
102 | BOOST_REQUIRE(option.value.size() == 1); |
103 | BOOST_CHECK(option.value.front() == value); |
104 | } |
105 | |
106 | void test_command_line() |
107 | { |
108 | options_description desc; |
109 | desc.add_options() |
110 | ("foo,f" , new untyped_value(), "" ) |
111 | // Explicit qualification is a workaround for vc6 |
112 | ("bar,b" , po::value<std::string>(), "" ) |
113 | ("baz" , new untyped_value()) |
114 | ("qux,plug*" , new untyped_value()) |
115 | ; |
116 | |
117 | const wchar_t* cmdline4_[] = { L"--foo=1\u0FF52" , L"-f4" , L"--bar=11" , |
118 | L"-b4" , L"--plug3=10" }; |
119 | vector<wstring> cmdline4 = sv(array: cmdline4_, |
120 | size: sizeof(cmdline4_)/sizeof(cmdline4_[0])); |
121 | vector<woption> a4 = |
122 | wcommand_line_parser(cmdline4).options(desc).run().options; |
123 | |
124 | BOOST_REQUIRE(a4.size() == 5); |
125 | |
126 | check_value(option: a4[0], name: "foo" , value: L"1\u0FF52" ); |
127 | check_value(option: a4[1], name: "foo" , value: L"4" ); |
128 | check_value(option: a4[2], name: "bar" , value: L"11" ); |
129 | check_value(option: a4[4], name: "qux" , value: L"10" ); |
130 | } |
131 | |
132 | // Since we've already tested conversion between parser encoding and |
133 | // option encoding, all we need to check for config file is that |
134 | // when reading wistream, it generates proper UTF8 data. |
135 | void test_config_file() |
136 | { |
137 | std::codecvt<wchar_t, char, mbstate_t>* facet = |
138 | new boost::program_options::detail::utf8_codecvt_facet; |
139 | locale::global(loc: locale(locale(), facet)); |
140 | |
141 | options_description desc; |
142 | |
143 | desc.add_options() |
144 | ("foo" , po::value<string>(), "unicode option" ) |
145 | ; |
146 | |
147 | std::wstringstream stream(L"foo = \x044F" ); |
148 | |
149 | variables_map vm; |
150 | store(options: parse_config_file(stream, desc), m&: vm); |
151 | |
152 | BOOST_CHECK(vm["foo" ].as<string>() == "\xD1\x8F" ); |
153 | } |
154 | |
155 | int main(int, char* []) |
156 | { |
157 | test_unicode_to_unicode(); |
158 | test_unicode_to_native(); |
159 | test_native_to_unicode(); |
160 | test_command_line(); |
161 | test_config_file(); |
162 | return 0; |
163 | } |
164 | |
165 | |