all unit tests: replaced BOOST_AUTO_UNIT_TEST with new SENF_AUTO_UNIT_TEST macro
[senf.git] / senf / Utils / 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 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 "Console.hh"
33
34 #include <senf/Utils/auto_unit_test.hh>
35 #include <boost/test/test_tools.hpp>
36
37 #define prefix_
38 ///////////////////////////////cc.p////////////////////////////////////////
39
40 namespace {
41
42     int cb1(int a, double b) { return int(a+b); }
43     double cb2() { return 1.2; }
44     void cb3(int i) { }
45     std::string cb4(std::ostream & os) { os << "text\n"; return "value"; }
46     void cb5(std::ostream & os, std::string const & v) { os << "Value: " << v << "\n"; }
47
48     struct TestParser 
49     {
50         void operator()(senf::console::ParseCommandInfo::TokensRange const &,
51                         std::string & out) const
52             { out = "true"; }
53     };
54
55     void testFormatter(double, std::ostream & os)
56     { os << "formatter"; }
57 }
58
59 SENF_AUTO_UNIT_TEST(parsedCommand)
60 {
61     senf::console::Executor executor;
62     senf::console::CommandParser parser;
63     senf::console::ScopedDirectory<> dir;
64     senf::console::root().add("test", dir);
65
66     {
67         std::stringstream ss;
68         dir.add("cb1", &cb1);
69         parser.parse("test/cb1 2 3.2", 
70                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
71         BOOST_CHECK_EQUAL( ss.str(), "5\n" );
72     }
73
74     {
75         std::stringstream ss;
76         dir.add("cb2", &cb2);
77         parser.parse("test/cb2",
78                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
79         BOOST_CHECK_EQUAL( ss.str(), "1.2\n" );
80     }
81
82     {
83         std::stringstream ss;
84         dir.add("cb3", &cb3);
85         parser.parse("test/cb3 234",
86                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
87         BOOST_CHECK_EQUAL( ss.str(), "" );
88     }
89
90     {
91         std::stringstream ss;
92         dir.add("cb4", &cb4);
93         parser.parse("test/cb4",
94                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
95         BOOST_CHECK_EQUAL( ss.str(), "text\n" "value\n" );
96     }
97
98     {
99         std::stringstream ss;
100         dir.add("cb5", &cb5);
101         parser.parse("test/cb5 1234",
102                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
103         BOOST_CHECK_EQUAL( ss.str(), "Value: 1234\n" );
104     }
105
106     {
107         std::stringstream ss;
108
109         BOOST_CHECK_THROW( 
110             parser.parse("test/cb1 2 3.2 foo", 
111                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )),
112             senf::console::SyntaxErrorException );
113
114         BOOST_CHECK_THROW(
115             parser.parse("test/cb1 2", 
116                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )),
117             senf::console::SyntaxErrorException );
118
119         BOOST_CHECK_THROW(
120             parser.parse("test/cb1 2 foo", 
121                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )),
122             senf::console::SyntaxErrorException );
123     }
124
125     {
126         namespace kw = senf::console::kw;
127         std::stringstream ss;
128
129         // Just for the fun of it, use a functor and not a function pointer as parser ...
130         dir.add("cb6", &cb5)
131             .arg( kw::parser = TestParser() );
132         SENF_CHECK_NO_THROW(
133             parser.parse("test/cb6 false",
134                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
135         BOOST_CHECK_EQUAL( ss.str(), "Value: true\n" );
136     }
137
138     {
139         std::stringstream ss;
140
141         // This tests adding boost::function objects and at the same time validates, that 
142         // compatible types also work
143         dir.add("cb7", boost::function<float()>(&cb2))
144             .formatter( &testFormatter );
145         SENF_CHECK_NO_THROW(
146             parser.parse("test/cb7",
147                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
148         BOOST_CHECK_EQUAL( ss.str(), "formatter\n" );
149     }
150
151     {
152         std::stringstream ss;
153
154         using namespace senf::console::kw;
155
156         dir.add("cb", &cb1)
157             .doc(
158                 "Ops fortunate, ops me ut orgia vociferatio contumax per, rudo re loco emitto\n"
159                 "intolerabiliter ita iugo. Subcribo gravo. Devenio luna fonticulus Castanea\n"
160                 "horum fascino Os interpretor non ipse conjuratio hora, qui filius denuntio ait\n"
161                 "sono te odium Anhelo. Dum Cedo audax celox alius una Agnosco hic, ibi retineo\n"
162                 "lux sto ioco. Per Re dono. Copiose reus scitus jus diligens sis scapulare\n"
163                 "Servitium transi." )
164
165             .shortdoc(
166                 "Ops fortunate." )
167
168             .overloadDoc(
169                 "Lo nam balnearius Opprimo Pennatus, no decentia sui, dicto esse se pulchritudo,\n"
170                 "pupa Sive res indifferenter. Captivo pa." )
171
172             .arg( description   = "Bar didelfrump di desgorb. Nu widsoflar brimeldrgf." )
173
174             .arg( name          = "checkup", 
175                   type_name     = "number",
176                   description   = "Florgel, dargel and durgel",
177                   default_value = 2.1,
178                   default_doc   = "(double) 2.1" );
179
180         senf::console::OverloadedCommandNode & cbNode (
181             dir.add("cb", &cb5)
182                 .overloadDoc(
183                     "Uus Primordia fundo falsidicus corium, diurnitas humo pro leto. Sui Ueraciter\n"
184                     "hio eruca lenis qua Agalmate ut fors penitentia. Iugum obdormio anxio nuncupo\n"
185                     "iam, in vos nam Custodi." ) 
186                 .arg( "text", default_value = "" ) );
187
188         (void) cbNode;
189
190         SENF_CHECK_NO_THROW(
191             parser.parse("test/cb 111 222.4",
192                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
193         SENF_CHECK_NO_THROW(
194             parser.parse("test/cb 222",
195                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
196         SENF_CHECK_NO_THROW(
197             parser.parse("test/cb foo",
198                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
199         SENF_CHECK_NO_THROW(
200             parser.parse("test/cb",
201                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
202
203         BOOST_CHECK_EQUAL( ss.str(), "333\n" "224\n" "Value: foo\n" "Value: \n" );
204
205         BOOST_CHECK_EQUAL( dir("cb").shorthelp(), "Ops fortunate." );
206     }
207
208     {
209         std::stringstream ss;
210         senf::console::root()["test"]("cb").help(ss);
211         BOOST_CHECK_EQUAL( 
212             ss.str(), 
213             "Usage:\n"
214             "    1- cb arg11:int [checkup:number]\n"
215             "    2- cb [text:string]\n"
216             "\n"
217             "With:\n"
218             "    arg11     Bar didelfrump di desgorb. Nu widsoflar brimeldrgf.\n"
219             "    checkup   Florgel, dargel and durgel\n"
220             "        default: (double) 2.1\n"
221             "    text      \n"
222             "        default: \"\"\n"
223             "\n"
224             "Ops fortunate, ops me ut orgia vociferatio contumax per, rudo re loco emitto\n"
225             "intolerabiliter ita iugo. Subcribo gravo. Devenio luna fonticulus Castanea\n"
226             "horum fascino Os interpretor non ipse conjuratio hora, qui filius denuntio ait\n"
227             "sono te odium Anhelo. Dum Cedo audax celox alius una Agnosco hic, ibi retineo\n"
228             "lux sto ioco. Per Re dono. Copiose reus scitus jus diligens sis scapulare\n"
229             "Servitium transi.\n"
230             "\n"
231             "Variant 1:\n"
232             "Lo nam balnearius Opprimo Pennatus, no decentia sui, dicto esse se pulchritudo,\n"
233             "pupa Sive res indifferenter. Captivo pa.\n"
234             "\n"
235             "Variant 2:\n"
236             "Uus Primordia fundo falsidicus corium, diurnitas humo pro leto. Sui Ueraciter\n"
237             "hio eruca lenis qua Agalmate ut fors penitentia. Iugum obdormio anxio nuncupo\n"
238             "iam, in vos nam Custodi.\n" );
239     }
240 }
241
242 namespace {
243
244     struct Test 
245     {
246         senf::console::ScopedDirectory<Test> dir;
247         std::string name_;
248
249         Test(std::string const & name) : dir(this), name_ (name) {
250             dir.add("name", &Test::name);
251         }
252
253         std::string name(std::string const & suffix) {
254             return name_ + suffix;
255         }
256     };
257
258 }
259
260 SENF_AUTO_UNIT_TEST(memberParsedCommand)
261 {
262     senf::console::Executor executor;
263     senf::console::CommandParser parser;
264     senf::console::ScopedDirectory<> dir;
265     senf::console::root().add("test", dir);
266     
267     {
268         Test obj ("bar");
269         dir.add("obj", obj.dir);
270         
271         std::stringstream ss;
272         parser.parse("test/obj/name \": foo\"",
273                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
274         BOOST_CHECK_EQUAL( ss.str(), "bar: foo\n" );
275     }
276 }
277
278 namespace {
279
280     senf::console::DirectoryNode::ptr dircb() 
281     {
282         senf::console::DirectoryNode & dir (
283             senf::console::root()["test"].mkdir("dircb"));
284         dir.add("cb1", &cb1);
285         return dir.thisptr();
286     }
287
288 }
289
290 SENF_AUTO_UNIT_TEST(directoryReturn)
291 {
292     senf::console::Executor executor;
293     senf::console::CommandParser parser;
294     senf::console::ScopedDirectory<> dir;
295     senf::console::root().add("test", dir);
296     dir.add("test", &dircb);
297
298     {
299         std::stringstream ss;
300         SENF_CHECK_NO_THROW(
301             parser.parse("test/test { ll; }",
302                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
303         BOOST_CHECK_EQUAL( ss.str(), 
304                            "<Directory at '/test/dircb'>\n"
305                            "cb1                         \n" );
306     }
307     
308 }
309
310 #ifdef COMPILE_CHECK
311
312 COMPILE_FAIL(argParser)
313 {
314     senf::console::ScopedDirectory<> dir;
315
316     // Fails, since there are only two arguments defined
317     dir.add("cb", &cb1)
318         .arg()
319         .arg()
320         .arg();
321 }
322
323 COMPILE_FAIL(defaultDoc)
324 {
325     senf::console::ScopedDirectory<> dir;
326     using namespace senf::console::kw;
327
328     // Fails, since default_value is missing but default_doc is given
329     dir.add("cb",&cb1)
330         .arg(default_doc = "doc");
331 }
332
333 #endif
334     
335 ///////////////////////////////cc.e////////////////////////////////////////
336 #undef prefix_
337
338 \f
339 // Local Variables:
340 // mode: c++
341 // fill-column: 100
342 // comment-column: 40
343 // c-file-style: "senf"
344 // indent-tabs-mode: nil
345 // ispell-local-dictionary: "american"
346 // compile-command: "scons -u test"
347 // End: