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