Console: Implement custom return-value formatter support
[senf.git] / Console / ParsedCommand.test.cc
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief ParsedCommand.test unit tests */
25
26 //#include "ParsedCommand.test.hh"
27 //#include "ParsedCommand.test.ih"
28
29 // Custom includes
30 #include <iostream>
31 #include <sstream>
32 #include "ParsedCommand.hh"
33 #include "Executor.hh"
34 #include "Parse.hh"
35 #include "ScopedDirectory.hh"
36
37 #include "../Utils/auto_unit_test.hh"
38 #include <boost/test/test_tools.hpp>
39
40 #define prefix_
41 ///////////////////////////////cc.p////////////////////////////////////////
42
43 namespace {
44
45     int cb1(int a, double b) { return int(a+b); }
46     double cb2(){ return 1.2; }
47     void cb3(int i) { }
48     std::string cb4(std::ostream & os) { os << "text\n"; return "value"; }
49     void cb5(std::ostream & os, std::string const & v) { os << "Value: " << v << "\n"; }
50
51     struct TestParser 
52     {
53         typedef senf::console::ParseCommandInfo::TokensRange const & first_argument_type;
54         typedef std::string & second_argument_type;
55         typedef void result_type;
56
57         result_type operator()(first_argument_type, second_argument_type out) const
58             { out = "true"; }
59     };
60
61     void testFormatter(double, std::ostream & os)
62     { os << "formatter"; }
63 }
64
65 BOOST_AUTO_UNIT_TEST(parsedCommand)
66 {
67     senf::console::Executor executor;
68     senf::console::CommandParser parser;
69     senf::console::ScopedDirectory<> dir;
70     senf::console::root().add("test", dir);
71
72     {
73         std::stringstream ss;
74         dir.add("cb1", &cb1);
75         parser.parse("test/cb1 2 3.2", 
76                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
77         BOOST_CHECK_EQUAL( ss.str(), "5\n" );
78     }
79
80     {
81         std::stringstream ss;
82         dir.add("cb2", &cb2);
83         parser.parse("test/cb2",
84                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
85         BOOST_CHECK_EQUAL( ss.str(), "1.2\n" );
86     }
87
88     {
89         std::stringstream ss;
90         dir.add("cb3", &cb3);
91         parser.parse("test/cb3 234",
92                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
93         BOOST_CHECK_EQUAL( ss.str(), "" );
94     }
95
96     {
97         std::stringstream ss;
98         dir.add("cb4", &cb4);
99         parser.parse("test/cb4",
100                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
101         BOOST_CHECK_EQUAL( ss.str(), "text\n" "value\n" );
102     }
103
104     {
105         std::stringstream ss;
106         dir.add("cb5", &cb5);
107         parser.parse("test/cb5 1234",
108                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
109         BOOST_CHECK_EQUAL( ss.str(), "Value: 1234\n" );
110     }
111
112     {
113         std::stringstream ss;
114
115         BOOST_CHECK_THROW( 
116             parser.parse("test/cb1 2 3.2 foo", 
117                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )),
118             senf::console::SyntaxErrorException );
119
120         BOOST_CHECK_THROW(
121             parser.parse("test/cb1 2", 
122                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )),
123             senf::console::SyntaxErrorException );
124
125         BOOST_CHECK_THROW(
126             parser.parse("test/cb1 2 foo", 
127                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )),
128             senf::console::SyntaxErrorException );
129     }
130
131     {
132         namespace kw = senf::console::kw;
133         std::stringstream ss;
134
135         // Just for the fun of it, use a functor and not a function pointer as parser ...
136         dir.add("cb6", &cb5)
137             .arg( kw::parser = TestParser() );
138         BOOST_CHECK_NO_THROW(
139             parser.parse("test/cb6 false",
140                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
141         BOOST_CHECK_EQUAL( ss.str(), "Value: true\n" );
142     }
143
144     {
145         std::stringstream ss;
146
147         dir.add("cb7", &cb2)
148             .formatter( &testFormatter );
149         BOOST_CHECK_NO_THROW(
150             parser.parse("test/cb7",
151                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
152         BOOST_CHECK_EQUAL( ss.str(), "formatter\n" );
153     }
154
155     {
156         std::stringstream ss;
157
158         using namespace senf::console::kw;
159
160         dir.add("cb", &cb1)
161             .doc(
162                 "Ops fortunate, ops me ut orgia vociferatio contumax per, rudo re loco emitto\n"
163                 "intolerabiliter ita iugo. Subcribo gravo. Devenio luna fonticulus Castanea\n"
164                 "horum fascino Os interpretor non ipse conjuratio hora, qui filius denuntio ait\n"
165                 "sono te odium Anhelo. Dum Cedo audax celox alius una Agnosco hic, ibi retineo\n"
166                 "lux sto ioco. Per Re dono. Copiose reus scitus jus diligens sis scapulare\n"
167                 "Servitium transi." )
168
169             .overloadDoc(
170                 "Lo nam balnearius Opprimo Pennatus, no decentia sui, dicto esse se pulchritudo,\n"
171                 "pupa Sive res indifferenter. Captivo pa." )
172
173             .arg( description   = "Bar didelfrump di desgorb. Nu widsoflar brimeldrgf." )
174
175             .arg( name          = "checkup", 
176                   type_name     = "number",
177                   description   = "Florgel, dargel and durgel",
178                   default_value = 2.1,
179                   default_doc   = "(double) 2.1" );
180
181         senf::console::OverloadedCommandNode & cbNode (
182             dir.add("cb", &cb5)
183                 .overloadDoc(
184                     "Uus Primordia fundo falsidicus corium, diurnitas humo pro leto. Sui Ueraciter\n"
185                     "hio eruca lenis qua Agalmate ut fors penitentia. Iugum obdormio anxio nuncupo\n"
186                     "iam, in vos nam Custodi." ) 
187                 .arg( "text", default_value = "" ) );
188
189         (void) cbNode;
190
191         BOOST_CHECK_NO_THROW(
192             parser.parse("test/cb 111 222.4",
193                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
194         BOOST_CHECK_NO_THROW(
195             parser.parse("test/cb 222",
196                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
197         BOOST_CHECK_NO_THROW(
198             parser.parse("test/cb foo",
199                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
200         BOOST_CHECK_NO_THROW(
201             parser.parse("test/cb",
202                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
203
204         BOOST_CHECK_EQUAL( ss.str(), "333\n" "224\n" "Value: foo\n" "Value: \n" );
205     }
206
207     {
208         std::stringstream ss;
209         senf::console::root()["test"]("cb").help(ss);
210         BOOST_CHECK_EQUAL( 
211             ss.str(), 
212             "Usage:\n"
213             "    1- cb arg11:int [checkup:number]\n"
214             "    2- cb [text:string]\n"
215             "\n"
216             "With:\n"
217             "    arg11     Bar didelfrump di desgorb. Nu widsoflar brimeldrgf.\n"
218             "    checkup   Florgel, dargel and durgel\n"
219             "        default: (double) 2.1\n"
220             "    text      \n"
221             "        default: (empty)\n"
222             "\n"
223             "Ops fortunate, ops me ut orgia vociferatio contumax per, rudo re loco emitto\n"
224             "intolerabiliter ita iugo. Subcribo gravo. Devenio luna fonticulus Castanea\n"
225             "horum fascino Os interpretor non ipse conjuratio hora, qui filius denuntio ait\n"
226             "sono te odium Anhelo. Dum Cedo audax celox alius una Agnosco hic, ibi retineo\n"
227             "lux sto ioco. Per Re dono. Copiose reus scitus jus diligens sis scapulare\n"
228             "Servitium transi.\n"
229             "\n"
230             "Variant 1:\n"
231             "Lo nam balnearius Opprimo Pennatus, no decentia sui, dicto esse se pulchritudo,\n"
232             "pupa Sive res indifferenter. Captivo pa.\n"
233             "\n"
234             "Variant 2:\n"
235             "Uus Primordia fundo falsidicus corium, diurnitas humo pro leto. Sui Ueraciter\n"
236             "hio eruca lenis qua Agalmate ut fors penitentia. Iugum obdormio anxio nuncupo\n"
237             "iam, in vos nam Custodi.\n" );
238     }
239 }
240
241 namespace {
242
243     struct Test 
244     {
245         senf::console::ScopedDirectory<Test> dir;
246         std::string name_;
247
248         Test(std::string const & name) : dir(this), name_ (name) {
249             dir.add("name", &Test::name);
250         }
251
252         std::string name(std::string const & suffix) {
253             return name_ + suffix;
254         }
255     };
256
257 }
258
259 BOOST_AUTO_UNIT_TEST(memberParsedCommand)
260 {
261     senf::console::Executor executor;
262     senf::console::CommandParser parser;
263     senf::console::ScopedDirectory<> dir;
264     senf::console::root().add("test", dir);
265     
266     {
267         Test obj ("bar");
268         dir.add("obj", obj.dir);
269         
270         std::stringstream ss;
271         parser.parse("test/obj/name \": foo\"",
272                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
273         BOOST_CHECK_EQUAL( ss.str(), "bar: foo\n" );
274     }
275 }
276
277 #ifdef COMPILE_CHECK
278
279 COMPILE_FAIL(argParser)
280 {
281     senf::console::ScopedDirectory<> dir;
282
283     // Fails, since there are only two arguments defined
284     dir.add("cb", &cb1)
285         .arg()
286         .arg()
287         .arg();
288 }
289
290 COMPILE_FAIL(defaultDoc)
291 {
292     senf::console::ScopedDirectory<> dir;
293     using namespace senf::console::kw;
294
295     // Fails, since default_value is missing but default_doc is given
296     dir.add("cb",&cb1)
297         .arg(default_doc = "doc");
298 }
299
300 #endif
301     
302 ///////////////////////////////cc.e////////////////////////////////////////
303 #undef prefix_
304
305 \f
306 // Local Variables:
307 // mode: c++
308 // fill-column: 100
309 // comment-column: 40
310 // c-file-style: "senf"
311 // indent-tabs-mode: nil
312 // ispell-local-dictionary: "american"
313 // compile-command: "scons -u test"
314 // End: