replaced some tabs with spaces
[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.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         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         BOOST_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         BOOST_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             .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         BOOST_CHECK_NO_THROW(
191             parser.parse("test/cb 111 222.4",
192                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
193         BOOST_CHECK_NO_THROW(
194             parser.parse("test/cb 222",
195                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
196         BOOST_CHECK_NO_THROW(
197             parser.parse("test/cb foo",
198                          boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
199         BOOST_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
206     {
207         std::stringstream ss;
208         senf::console::root()["test"]("cb").help(ss);
209         BOOST_CHECK_EQUAL( 
210             ss.str(), 
211             "Usage:\n"
212             "    1- cb arg11:int [checkup:number]\n"
213             "    2- cb [text:string]\n"
214             "\n"
215             "With:\n"
216             "    arg11     Bar didelfrump di desgorb. Nu widsoflar brimeldrgf.\n"
217             "    checkup   Florgel, dargel and durgel\n"
218             "        default: (double) 2.1\n"
219             "    text      \n"
220             "        default: (empty)\n"
221             "\n"
222             "Ops fortunate, ops me ut orgia vociferatio contumax per, rudo re loco emitto\n"
223             "intolerabiliter ita iugo. Subcribo gravo. Devenio luna fonticulus Castanea\n"
224             "horum fascino Os interpretor non ipse conjuratio hora, qui filius denuntio ait\n"
225             "sono te odium Anhelo. Dum Cedo audax celox alius una Agnosco hic, ibi retineo\n"
226             "lux sto ioco. Per Re dono. Copiose reus scitus jus diligens sis scapulare\n"
227             "Servitium transi.\n"
228             "\n"
229             "Variant 1:\n"
230             "Lo nam balnearius Opprimo Pennatus, no decentia sui, dicto esse se pulchritudo,\n"
231             "pupa Sive res indifferenter. Captivo pa.\n"
232             "\n"
233             "Variant 2:\n"
234             "Uus Primordia fundo falsidicus corium, diurnitas humo pro leto. Sui Ueraciter\n"
235             "hio eruca lenis qua Agalmate ut fors penitentia. Iugum obdormio anxio nuncupo\n"
236             "iam, in vos nam Custodi.\n" );
237     }
238 }
239
240 namespace {
241
242     struct Test 
243     {
244         senf::console::ScopedDirectory<Test> dir;
245         std::string name_;
246
247         Test(std::string const & name) : dir(this), name_ (name) {
248             dir.add("name", &Test::name);
249         }
250
251         std::string name(std::string const & suffix) {
252             return name_ + suffix;
253         }
254     };
255
256 }
257
258 BOOST_AUTO_UNIT_TEST(memberParsedCommand)
259 {
260     senf::console::Executor executor;
261     senf::console::CommandParser parser;
262     senf::console::ScopedDirectory<> dir;
263     senf::console::root().add("test", dir);
264     
265     {
266         Test obj ("bar");
267         dir.add("obj", obj.dir);
268         
269         std::stringstream ss;
270         parser.parse("test/obj/name \": foo\"",
271                      boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 ));
272         BOOST_CHECK_EQUAL( ss.str(), "bar: foo\n" );
273     }
274 }
275
276 #ifdef COMPILE_CHECK
277
278 COMPILE_FAIL(argParser)
279 {
280     senf::console::ScopedDirectory<> dir;
281
282     // Fails, since there are only two arguments defined
283     dir.add("cb", &cb1)
284         .arg()
285         .arg()
286         .arg();
287 }
288
289 COMPILE_FAIL(defaultDoc)
290 {
291     senf::console::ScopedDirectory<> dir;
292     using namespace senf::console::kw;
293
294     // Fails, since default_value is missing but default_doc is given
295     dir.add("cb",&cb1)
296         .arg(default_doc = "doc");
297 }
298
299 #endif
300     
301 ///////////////////////////////cc.e////////////////////////////////////////
302 #undef prefix_
303
304 \f
305 // Local Variables:
306 // mode: c++
307 // fill-column: 100
308 // comment-column: 40
309 // c-file-style: "senf"
310 // indent-tabs-mode: nil
311 // ispell-local-dictionary: "american"
312 // compile-command: "scons -u test"
313 // End: