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