test.cpp 16.6 KB
Newer Older
1 2 3 4
/**
 * Just a very simple test suite, by hand, using assert()
 */

louiz’'s avatar
louiz’ committed
5
#include <xmpp/xmpp_component.hpp>
louiz’'s avatar
louiz’ committed
6
#include <utils/timed_events.hpp>
7
#include <xmpp/xmpp_parser.hpp>
8
#include <utils/encoding.hpp>
louiz’'s avatar
louiz’ committed
9
#include <logger/logger.hpp>
10 11
#include <config/config.hpp>
#include <bridge/colors.hpp>
louiz’'s avatar
louiz’ committed
12
#include <utils/tolower.hpp>
louiz’'s avatar
louiz’ committed
13
#include <utils/revstr.hpp>
14
#include <irc/irc_user.hpp>
15 16
#include <utils/split.hpp>
#include <xmpp/jid.hpp>
louiz’'s avatar
louiz’ committed
17
#include <irc/iid.hpp>
18 19
#include <string.h>

20
#include <iostream>
louiz’'s avatar
louiz’ committed
21
#include <thread>
22
#include <vector>
23

24
#undef NDEBUG
25
#include <assert.h>
26

27 28 29
static const std::string color("");
static const std::string reset("");

30 31
int main()
{
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

  /**
   * Config
   */
  std::cout << color << "Testing config…" << reset << std::endl;
  Config::filename = "test.cfg";
  Config::file_must_exist = false;
  Config::set("coucou", "bonjour", true);
  Config::close();

  bool error = false;
  try
    {
      Config::file_must_exist = true;
      assert(Config::get("coucou", "") == "bonjour");
      assert(Config::get("does not exist", "default") == "default");
      Config::close();
    }
  catch (const std::ios::failure& e)
    {
      error = true;
    }
  assert(error == false);

  Config::set("log_level", "2");
  Config::set("log_file", "");

  std::cout << color << "Testing logging…" << reset << std::endl;
  log_debug("If you see this, the test FAILED.");
  log_info("If you see this, the test FAILED.");
louiz’'s avatar
louiz’ committed
62
  log_warning("You must see this message. And the next one too.");
63 64 65
  log_error("It’s not an error, don’t worry, the test passed.");


louiz’'s avatar
louiz’ committed
66 67 68 69 70
  /**
   * Timed events
   */
  std::cout << color << "Testing timed events…" << reset << std::endl;
  // No event.
71 72
  assert(TimedEventsManager::instance().get_timeout() == utils::no_timeout);
  assert(TimedEventsManager::instance().execute_expired_events() == 0);
louiz’'s avatar
louiz’ committed
73 74

  // Add a single event
75
  TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 50ms, [](){ std::cout << "Timeout expired" << std::endl; }));
louiz’'s avatar
louiz’ committed
76
  // The event should not yet be expired
77 78 79
  assert(TimedEventsManager::instance().get_timeout() > 0ms);
  assert(TimedEventsManager::instance().execute_expired_events() == 0);
  std::chrono::milliseconds timoute = TimedEventsManager::instance().get_timeout();
louiz’'s avatar
louiz’ committed
80 81 82 83
  std::cout << "Sleeping for " << timoute.count() << "ms" << std::endl;
  std::this_thread::sleep_for(timoute);

  // Event is now expired
84 85
  assert(TimedEventsManager::instance().execute_expired_events() == 1);
  assert(TimedEventsManager::instance().get_timeout() == utils::no_timeout);
louiz’'s avatar
louiz’ committed
86

87
  // Test canceling events
88 89 90 91 92 93 94 95 96
  TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 100ms, [](){ }, "un"));
  TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 200ms, [](){ }, "deux"));
  TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 300ms, [](){ }, "deux"));
  assert(TimedEventsManager::instance().get_timeout() > 0ms);
  assert(TimedEventsManager::instance().size() == 3);
  assert(TimedEventsManager::instance().cancel("un") == 1);
  assert(TimedEventsManager::instance().size() == 2);
  assert(TimedEventsManager::instance().cancel("deux") == 2);
  assert(TimedEventsManager::instance().get_timeout() == utils::no_timeout);
97

98 99 100
  /**
   * Encoding
   */
101
  std::cout << color << "Testing encoding…" << reset << std::endl;
102 103 104 105 106 107 108
  const char* valid = "C̡͔͕̩͙̽ͫ̈́ͥ̿̆ͧ̚r̸̩̘͍̻͖̆͆͛͊̉̕͡o͇͈̳̤̱̊̈͢q̻͍̦̮͕ͥͬͬ̽ͭ͌̾ͅǔ͉͕͇͚̙͉̭͉̇̽ȇ͈̮̼͍͔ͣ͊͞͝ͅ ͫ̾ͪ̓ͥ̆̋̔҉̢̦̠͈͔̖̲̯̦ụ̶̯͐̃̋ͮ͆͝n̬̱̭͇̻̱̰̖̤̏͛̏̿̑͟ë́͐҉̸̥̪͕̹̻̙͉̰ ̹̼̱̦̥ͩ͑̈́͑͝ͅt͍̥͈̹̝ͣ̃̔̈̔ͧ̕͝ḙ̸̖̟̙͙ͪ͢ų̯̞̼̲͓̻̞͛̃̀́b̮̰̗̩̰̊̆͗̾̎̆ͯ͌͝.̗̙͎̦ͫ̈́ͥ͌̈̓ͬ";
  assert(utils::is_valid_utf8(valid) == true);
  const char* invalid = "\xF0\x0F";
  assert(utils::is_valid_utf8(invalid) == false);
  const char* invalid2 = "\xFE\xFE\xFF\xFF";
  assert(utils::is_valid_utf8(invalid2) == false);

109 110
  std::string in = "Biboumi ╯°□°)╯︵ ┻━┻";
  std::cout << in << std::endl;
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
  assert(utils::is_valid_utf8(in.c_str()) == true);
  std::string res = utils::convert_to_utf8(in, "UTF-8");
  assert(utils::is_valid_utf8(res.c_str()) == true && res == in);

  std::string original_utf8("couc¥ou");
  std::string original_latin1("couc\xa5ou");

  // When converting back to utf-8
  std::string from_latin1 = utils::convert_to_utf8(original_latin1.c_str(), "ISO-8859-1");
  assert(from_latin1 == original_utf8);

  // Check the behaviour when the decoding fails (here because we provide a
  // wrong charset)
  std::string from_ascii = utils::convert_to_utf8(original_latin1, "US-ASCII");
  assert(from_ascii == "couc�ou");
126
  std::cout << from_ascii << std::endl;
127

128 129 130 131 132
  std::string without_ctrl_char("𤭢€¢$");
  assert(utils::remove_invalid_xml_chars(without_ctrl_char) == without_ctrl_char);
  assert(utils::remove_invalid_xml_chars(in) == in);
  assert(utils::remove_invalid_xml_chars("\acouco\u0008u\uFFFEt\uFFFFe\r\n♥") == "coucoute\r\n♥");

louiz’'s avatar
louiz’ committed
133 134 135
  /**
   * Id generation
   */
136 137 138 139 140 141 142 143
  std::cout << color << "Testing id generation…" << reset << std::endl;
  const std::string first_uuid = XmppComponent::next_id();
  const std::string second_uuid = XmppComponent::next_id();
  std::cout << first_uuid << std::endl;
  std::cout << second_uuid << std::endl;
  assert(first_uuid.size() == 36);
  assert(second_uuid.size() == 36);
  assert(first_uuid != second_uuid);
louiz’'s avatar
louiz’ committed
144

145 146 147
  /**
   * Utils
   */
148
  std::cout << color << "Testing utils…" << reset << std::endl;
149 150 151 152 153 154 155 156 157 158 159 160
  std::vector<std::string> splitted = utils::split("a::a", ':', false);
  assert(splitted.size() == 2);
  splitted = utils::split("a::a", ':', true);
  assert(splitted.size() == 3);
  assert(splitted[0] == "a");
  assert(splitted[1] == "");
  assert(splitted[2] == "a");
  splitted = utils::split("\na", '\n', true);
  assert(splitted.size() == 2);
  assert(splitted[0] == "");
  assert(splitted[1] == "a");

louiz’'s avatar
louiz’ committed
161 162 163 164
  const std::string lowercase = utils::tolower("CoUcOu LeS CoPaiNs ♥");
  std::cout << lowercase << std::endl;
  assert(lowercase == "coucou les copains ♥");

louiz’'s avatar
louiz’ committed
165 166 167
  const std::string ltr = "coucou";
  assert(utils::revstr(ltr) == "uocuoc");

168 169 170
  /**
   * XML parsing
   */
171
  std::cout << color << "Testing XML parsing…" << reset << std::endl;
172
  XmppParser xml;
173
  const std::string doc = "<stream xmlns='stream_ns'><stanza b='c'>inner<child1><grandchild/></child1><child2 xmlns='child2_ns'/>tail</stanza></stream>";
174 175 176 177 178 179 180 181 182 183 184 185 186
  auto check_stanza = [](const Stanza& stanza)
    {
      assert(stanza.get_name() == "stanza");
      assert(stanza.get_tag("xmlns") == "stream_ns");
      assert(stanza.get_tag("b") == "c");
      assert(stanza.get_inner() == "inner");
      assert(stanza.get_tail() == "");
      assert(stanza.get_child("child1", "stream_ns") != nullptr);
      assert(stanza.get_child("child2", "stream_ns") == nullptr);
      assert(stanza.get_child("child2", "child2_ns") != nullptr);
      assert(stanza.get_child("child2", "child2_ns")->get_tail() == "tail");
    };
  xml.add_stanza_callback([check_stanza](const Stanza& stanza)
187
      {
188
        std::cout << stanza.to_string() << std::endl;
189 190 191 192
        check_stanza(stanza);
        // Do the same checks on a copy of that stanza.
        Stanza copy(stanza);
        check_stanza(copy);
193 194
      });
  xml.feed(doc.data(), doc.size(), true);
195

196 197 198 199 200 201 202 203
  const std::string doc2 = "<stream xmlns='s'><stanza>coucou\r\n\a</stanza></stream>";
  xml.add_stanza_callback([](const Stanza& stanza)
      {
        std::cout << stanza.to_string() << std::endl;
        assert(stanza.get_inner() == "coucou\r\n");
      });
  xml.feed(doc2.data(), doc.size(), true);

louiz’'s avatar
louiz’ committed
204 205 206
  /**
   * XML escape/escape
   */
207
  std::cout << color << "Testing XML escaping…" << reset << std::endl;
louiz’'s avatar
louiz’ committed
208 209 210 211
  const std::string unescaped = "'coucou'<cc>/&\"gaga\"";
  assert(xml_escape(unescaped) == "&apos;coucou&apos;&lt;cc&gt;/&amp;&quot;gaga&quot;");
  assert(xml_unescape(xml_escape(unescaped)) == unescaped);

212 213 214 215 216 217 218 219 220 221 222 223 224
  /**
   * Irc user parsing
   */
  const std::map<char, char> prefixes{{'!', 'a'}, {'@', 'o'}};

  IrcUser user1("!nick!~some@host.bla", prefixes);
  assert(user1.nick == "nick");
  assert(user1.host == "~some@host.bla");
  assert(user1.modes.size() == 1);
  assert(user1.modes.find('a') != user1.modes.end());
  IrcUser user2("coucou!~other@host.bla", prefixes);
  assert(user2.nick == "coucou");
  assert(user2.host == "~other@host.bla");
225
  assert(user2.modes.empty());
226 227
  assert(user2.modes.find('a') == user2.modes.end());

228 229 230
  /**
   * Colors conversion
   */
231
  std::cout << color << "Testing IRC colors conversion…" << reset << std::endl;
232 233 234
  std::unique_ptr<XmlNode> xhtml;
  std::string cleaned_up;

235 236 237 238
  std::tie(cleaned_up, xhtml) = irc_format_to_xhtmlim("bold");
  std::cout << xhtml->to_string() << std::endl;
  assert(xhtml && xhtml->to_string() == "<body xmlns='http://www.w3.org/1999/xhtml'><span style='font-weight:bold;'>bold</span></body>");

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
  std::tie(cleaned_up, xhtml) =
    irc_format_to_xhtmlim("normalboldunder-and-boldbold normal"
                          "5red,5default-on-red10,2cyan-on-blue");
  assert(xhtml);
  assert(xhtml->to_string() == "<body xmlns='http://www.w3.org/1999/xhtml'>normal<span style='font-weight:bold;'>bold</span><span style='font-weight:bold;text-decoration:underline;'>under-and-bold</span><span style='font-weight:bold;'>bold</span> normal<span style='color:red;'>red</span><span style='background-color:red;'>default-on-red</span><span style='color:cyan;background-color:blue;'>cyan-on-blue</span></body>");
  assert(cleaned_up == "normalboldunder-and-boldbold normalreddefault-on-redcyan-on-blue");

  std::tie(cleaned_up, xhtml) = irc_format_to_xhtmlim("normal");
  assert(!xhtml && cleaned_up == "normal");

  std::tie(cleaned_up, xhtml) = irc_format_to_xhtmlim("");
  assert(xhtml && !xhtml->has_children() && cleaned_up.empty());

  std::tie(cleaned_up, xhtml) = irc_format_to_xhtmlim(",a");
  assert(xhtml && !xhtml->has_children() && cleaned_up == "a");

  std::tie(cleaned_up, xhtml) = irc_format_to_xhtmlim(",");
  assert(xhtml && !xhtml->has_children() && cleaned_up.empty());

258 259 260 261
  std::tie(cleaned_up, xhtml) = irc_format_to_xhtmlim("[\x1D13dolphin-emu/dolphin\x1D] 03foo commented on #283 (Add support for the guide button to XInput): 02http://example.com");
  assert(xhtml->to_string() == "<body xmlns='http://www.w3.org/1999/xhtml'>[<span style='font-style:italic;'/><span style='font-style:italic;color:lightmagenta;'>dolphin-emu/dolphin</span><span style='color:lightmagenta;'>] </span><span style='color:green;'>foo</span> commented on #283 (Add support for the guide button to XInput): <span style='text-decoration:underline;'/><span style='text-decoration:underline;color:blue;'>http://example.com</span><span style='text-decoration:underline;'/></body>");
  assert(cleaned_up == "[dolphin-emu/dolphin] foo commented on #283 (Add support for the guide button to XInput): http://example.com");

262 263 264 265
  std::tie(cleaned_up, xhtml) = irc_format_to_xhtmlim("0e46ab by 03Pierre Dindon [090|091|040] 02http://example.net/Ojrh4P media: avoid pop-in effect when loading thumbnails by specifying an explicit size");
  assert(cleaned_up == "0e46ab by Pierre Dindon [0|1|0] http://example.net/Ojrh4P media: avoid pop-in effect when loading thumbnails by specifying an explicit size");
  assert(xhtml->to_string() == "<body xmlns='http://www.w3.org/1999/xhtml'>0e46ab by <span style='color:green;'>Pierre Dindon</span> [<span style='color:lightgreen;'>0</span>|<span style='color:lightgreen;'>1</span>|<span style='color:indianred;'>0</span>] <span style='text-decoration:underline;'/><span style='text-decoration:underline;color:blue;'>http://example.net/Ojrh4P</span><span style='text-decoration:underline;'/> media: avoid pop-in effect when loading thumbnails by specifying an explicit size</body>");

Link Mauve's avatar
Link Mauve committed
266 267 268 269
  std::tie(cleaned_up, xhtml) = irc_format_to_xhtmlim("test\ncoucou");
  assert(cleaned_up == "test\ncoucou");
  assert(xhtml->to_string() == "<body xmlns='http://www.w3.org/1999/xhtml'>test<br/>coucou</body>");

Link Mauve's avatar
Link Mauve committed
270 271 272
  /**
   * JID parsing
   */
273
  std::cout << color << "Testing JID parsing…" << reset << std::endl;
Link Mauve's avatar
Link Mauve committed
274 275
  // Full JID
  Jid jid1("♥@ツ.coucou/coucou@coucou/coucou");
276
  std::cout << jid1.local << "@" << jid1.domain << "/" << jid1.resource << std::endl;
Link Mauve's avatar
Link Mauve committed
277 278 279 280 281 282
  assert(jid1.local == "♥");
  assert(jid1.domain == "ツ.coucou");
  assert(jid1.resource == "coucou@coucou/coucou");

  // Domain and resource
  Jid jid2("ツ.coucou/coucou@coucou/coucou");
283
  std::cout << jid2.local << "@" << jid2.domain << "/" << jid2.resource << std::endl;
Link Mauve's avatar
Link Mauve committed
284 285 286 287
  assert(jid2.local == "");
  assert(jid2.domain == "ツ.coucou");
  assert(jid2.resource == "coucou@coucou/coucou");

288
  // Jidprep
louiz’'s avatar
louiz’ committed
289
  const std::string& badjid("~zigougou™@EpiK-7D9D1FDE.poez.io/Boujour/coucou/slt™");
290
  const std::string correctjid = jidprep(badjid);
louiz’'s avatar
louiz’ committed
291
  std::cout << correctjid << std::endl;
louiz’'s avatar
louiz’ committed
292
  assert(correctjid == "~zigougoutm@epik-7d9d1fde.poez.io/Boujour/coucou/sltTM");
louiz’'s avatar
louiz’ committed
293 294 295 296
  // Check that the cache do not break things when we prep the same string
  // multiple times
  assert(jidprep(badjid) == "~zigougoutm@epik-7d9d1fde.poez.io/Boujour/coucou/sltTM");
  assert(jidprep(badjid) == "~zigougoutm@epik-7d9d1fde.poez.io/Boujour/coucou/sltTM");
297 298 299 300 301

  const std::string& badjid2("Zigougou@poez.io");
  const std::string correctjid2 = jidprep(badjid2);
  std::cout << correctjid2 << std::endl;
  assert(correctjid2 == "zigougou@poez.io");
302

louiz’'s avatar
louiz’ committed
303 304 305
  /**
   * IID parsing
   */
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
  {
    std::cout << color << "Testing IID parsing…" << reset << std::endl;
    Iid iid1("foo!irc.example.org");
    std::cout << std::to_string(iid1) << std::endl;
    assert(std::to_string(iid1) == "foo!irc.example.org");
    assert(iid1.get_local() == "foo");
    assert(iid1.get_server() == "irc.example.org");
    assert(!iid1.is_channel);
    assert(iid1.is_user);

    Iid iid2("#test%irc.example.org");
    std::cout << std::to_string(iid2) << std::endl;
    assert(std::to_string(iid2) == "#test%irc.example.org");
    assert(iid2.get_local() == "#test");
    assert(iid2.get_server() == "irc.example.org");
    assert(iid2.is_channel);
    assert(!iid2.is_user);

    Iid iid3("%irc.example.org");
    std::cout << std::to_string(iid3) << std::endl;
    assert(std::to_string(iid3) == "%irc.example.org");
    assert(iid3.get_local() == "");
    assert(iid3.get_server() == "irc.example.org");
    assert(iid3.is_channel);
    assert(!iid3.is_user);

    Iid iid4("irc.example.org");
    std::cout << std::to_string(iid4) << std::endl;
    assert(std::to_string(iid4) == "irc.example.org");
    assert(iid4.get_local() == "");
    assert(iid4.get_server() == "irc.example.org");
    assert(!iid4.is_channel);
    assert(!iid4.is_user);

    Iid iid5("nick!");
    std::cout << std::to_string(iid5) << std::endl;
    assert(std::to_string(iid5) == "nick!");
    assert(iid5.get_local() == "nick");
    assert(iid5.get_server() == "");
    assert(!iid5.is_channel);
    assert(iid5.is_user);

    Iid iid6("##channel%");
    std::cout << std::to_string(iid6) << std::endl;
    assert(std::to_string(iid6) == "##channel%");
    assert(iid6.get_local() == "##channel");
    assert(iid6.get_server() == "");
    assert(iid6.is_channel);
    assert(!iid6.is_user);
  }

  {
    std::cout << color << "Testing IID parsing with a fixed server configured…" << reset << std::endl;
    // Now do the same tests, but with a configured fixed_irc_server
    Config::set("fixed_irc_server", "fixed.example.com", false);

    Iid iid1("foo!irc.example.org");
    std::cout << std::to_string(iid1) << std::endl;
    assert(std::to_string(iid1) == "foo!");
    assert(iid1.get_local() == "foo");
    assert(iid1.get_server() == "fixed.example.com");
    assert(!iid1.is_channel);
    assert(iid1.is_user);

    Iid iid2("#test%irc.example.org");
    std::cout << std::to_string(iid2) << std::endl;
372 373
    assert(std::to_string(iid2) == "#test%irc.example.org");
    assert(iid2.get_local() == "#test%irc.example.org");
374 375 376 377
    assert(iid2.get_server() == "fixed.example.com");
    assert(iid2.is_channel);
    assert(!iid2.is_user);

378
    // Note that it is impossible to adress the IRC server directly, or to
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
    // use the virtual channel, in that mode

    // Iid iid3("%irc.example.org");
    // Iid iid4("irc.example.org");

    Iid iid5("nick!");
    std::cout << std::to_string(iid5) << std::endl;
    assert(std::to_string(iid5) == "nick!");
    assert(iid5.get_local() == "nick");
    assert(iid5.get_server() == "fixed.example.com");
    assert(!iid5.is_channel);
    assert(iid5.is_user);

    Iid iid6("##channel%");
    std::cout << std::to_string(iid6) << std::endl;
394 395
    assert(std::to_string(iid6) == "##channel%");
    assert(iid6.get_local() == "##channel%");
396 397 398 399
    assert(iid6.get_server() == "fixed.example.com");
    assert(iid6.is_channel);
    assert(!iid6.is_user);
  }
louiz’'s avatar
louiz’ committed
400

401 402
  return 0;
}