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