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