
/*

  KLayout Layout Viewer
  Copyright (C) 2006-2025 Matthias Koefferlein

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/


#include "tlString.h"
#include "tlTimer.h"
#include "tlUnitTest.h"

#define _USE_MATH_DEFINES // for MSVC
#include <math.h>
#include <clocale>

using namespace tl;

static std::string norm_exp (const std::string &s)
{
  return tl::replaced (tl::replaced (s, "e+006", "e+06"), "E+006", "E+06");
}

TEST(1)
{
  EXPECT_EQ (to_string (12.5), "12.5");
  EXPECT_EQ (tl::sprintf ("%.2f", 12.5), "12.50");
  EXPECT_EQ (to_string (int (12)), "12");
  EXPECT_EQ (to_string (long (12)), "12");
  EXPECT_EQ (to_string ((unsigned int)12), "12");
  EXPECT_EQ (to_string ((unsigned long)12), "12");
  EXPECT_EQ (to_string ((char *)" 12"), " 12");
  EXPECT_EQ (to_string (" 12", 2), " 1");
  EXPECT_EQ (to_string ((unsigned char *)" 12"), " 12");
  EXPECT_EQ (to_string (std::string (" 12")), " 12");

  EXPECT_EQ (norm_exp (tl::sprintf("%g %e %f",M_PI,M_PI*1e6,M_PI*0.001)), "3.14159 3.141593e+06 0.003142");
  EXPECT_EQ (norm_exp (tl::sprintf("%G %E %F",M_PI*1e6,M_PI*1e6,M_PI*1e6)), "3.14159E+06 3.141593E+06 3141592.653590");
  EXPECT_EQ (norm_exp (tl::sprintf("%-15g %015.8e %15.12f %g",M_PI,M_PI*1e6,M_PI*0.001,M_PI)), "3.14159         03.14159265e+06  0.003141592654 3.14159");
  EXPECT_EQ (norm_exp (tl::sprintf("%-15g %015.8E %15.12f %g",M_PI,M_PI*1e6,M_PI*0.001,M_PI)), "3.14159         03.14159265E+06  0.003141592654 3.14159");
  EXPECT_EQ (tl::sprintf("%-5s %5s %x %u %d (%s)","a","b",1234,2345,3456), "a         b 4d2 2345 3456 ()");
  EXPECT_EQ (tl::sprintf("%lu %llu %02x", 1, 2, 167), "1 2 a7");
  EXPECT_EQ (tl::sprintf("%lu %llu %02X", 1, 2, 761), "1 2 2F9");
  EXPECT_EQ (tl::sprintf("%c%c", 'a', 'X'), "aX");
}

TEST(1a)
{
  double d;

  from_string("-.10500", d);
  EXPECT_EQ (to_string(d), "-0.105");

  from_string("000.105", d);
  EXPECT_EQ (to_string(d), "0.105");

  from_string("10", d);
  EXPECT_EQ (to_string(d), "10");

  from_string("-0010", d);
  EXPECT_EQ (to_string(d), "-10");

  from_string("-15.", d);
  EXPECT_EQ (to_string(d), "-15");

  from_string("-15.000e-1", d);
  EXPECT_EQ (to_string(d), "-1.5");

  from_string("-15.000E+1", d);
  EXPECT_EQ (to_string(d), "-150");

  from_string_ext("-15.000E+1", d);
  EXPECT_EQ (to_string(d), "-150");

  from_string_ext("25400/25.4", d);
  EXPECT_EQ (to_string(d), "1000");

  from_string_ext("25400/(25+0.4)", d);
  EXPECT_EQ (to_string(d), "1000");

  from_string_ext(" 25400   / (25  + 0.4 )   ", d);
  EXPECT_EQ (to_string(d), "1000");

  from_string("1E+03", d);
  EXPECT_EQ (to_string(d), "1000");

  from_string("11E3", d);
  EXPECT_EQ (to_string(d), "11000");

  from_string("0.0515e+003", d);
  EXPECT_EQ (to_string(d), "51.5");

  tl::Extractor ex ("    -15.000e-1x");
  double x;
  ex.read (x);
  EXPECT_EQ (to_string(x), "-1.5");
  ex.expect ("x");
}

TEST(2)
{
  long l;
  unsigned long ul;
  int i;
  unsigned int ui;
  std::string s;
  double d;
  bool error;

  from_string ("12.5", d);
  EXPECT_EQ (d, 12.5);
  from_string ("-12.5", d);
  EXPECT_EQ (d, -12.5);
  from_string ("-12.5e2", d);
  EXPECT_EQ (d, -12.5e2);
  from_string ("   -12.5e2    ", d);
  EXPECT_EQ (d, -12.5e2);
  error = false;
  try { from_string ("a", d); } catch (...) { error = true; }
  EXPECT_EQ (error, true);
  error = false;
  try { from_string ("12a", d); } catch (...) { error = true; }
  EXPECT_EQ (error, true);
  
  from_string ("   12   ", ul);
  EXPECT_EQ (ul, (unsigned int) 12);
  from_string_ext ("   12   ", ul);
  EXPECT_EQ (ul, (unsigned int) 12);
  error = false;
  try { from_string ("a", ul); } catch (...) { error = true; }
  EXPECT_EQ (error, true);
  error = false;
  try { from_string ("-12", ul); } catch (...) { error = true; }
  EXPECT_EQ (error, true);

  from_string ("   12   ", l);
  EXPECT_EQ (l, 12);
  from_string_ext ("   12   ", l);
  EXPECT_EQ (l, 12);
  error = false;
  try { from_string ("a", l); } catch (...) { error = true; }
  EXPECT_EQ (error, true);

  from_string ("   12   ", ui);
  EXPECT_EQ (ui, (unsigned int) 12);
  from_string_ext ("   12   ", ui);
  EXPECT_EQ (ui, (unsigned int) 12);
  error = false;
  try { from_string ("a", ui); } catch (...) { error = true; }
  EXPECT_EQ (error, true);
  error = false;
  try { from_string ("-12", ui); } catch (...) { error = true; }
  EXPECT_EQ (error, true);

  from_string ("   12   ", i);
  EXPECT_EQ (i, 12);
  from_string_ext ("   12   ", i);
  EXPECT_EQ (i, 12);
  error = false;
  try { from_string ("a", i); } catch (...) { error = true; }
  EXPECT_EQ (error, true);

  from_string ("  12", s);
  EXPECT_EQ (s, "  12");
}

TEST(3)
{
  EXPECT_EQ (trim ("   12   "), "12");
  EXPECT_EQ (trim ("   1 2   "), "1 2");
  EXPECT_EQ (trim ("   1 2"), "1 2");
  EXPECT_EQ (trim ("1 2"), "1 2");
}

TEST(4)
{
  tl::string s;
  EXPECT_EQ (std::string (s.c_str ()), "");
  EXPECT_EQ (s.std_str (), "");
  EXPECT_EQ (s.size (), size_t (0));
  EXPECT_EQ (s.capacity (), size_t (0));

  s = "abc";
  EXPECT_EQ (std::string (s.c_str ()), "abc");
  EXPECT_EQ (s.std_str (), "abc");
  EXPECT_EQ (s.size (), size_t (3));
  EXPECT_EQ (s.capacity (), size_t (3));

  s.assign ("abc", 1, 2);
  EXPECT_EQ (std::string (s.c_str ()), "b");
  EXPECT_EQ (s == "b", true);
  EXPECT_EQ (s != "b", false);
  EXPECT_EQ (s == "a", false);
  EXPECT_EQ (s == "", false);
  EXPECT_EQ (s > "", true);
  EXPECT_EQ (s > "a", true);
  EXPECT_EQ (s > "b", false);
  EXPECT_EQ (s < "", false);
  EXPECT_EQ (s < "b", false);
  EXPECT_EQ (s < "ba", true);
  EXPECT_EQ (s < "c", true);
  EXPECT_EQ (s.std_str (), "b");
  EXPECT_EQ (s.size (), size_t (1));
  EXPECT_EQ (s.capacity (), size_t (3));

  s = std::string ("abcdef");
  EXPECT_EQ (s.std_str (), "abcdef");
  EXPECT_EQ (s.size (), size_t (6));
  EXPECT_EQ (s.capacity (), size_t (6));

  s = std::string ();
  EXPECT_EQ (s.std_str (), "");
  EXPECT_EQ (s.size (), size_t (0));
  EXPECT_EQ (s.capacity (), size_t (6));

  s = "xyz";
  EXPECT_EQ (s.std_str (), "xyz");
  EXPECT_EQ (s.size (), size_t (3));
  EXPECT_EQ (s.capacity (), size_t (6));

  s.clear ();
  EXPECT_EQ (s.std_str (), "");
  EXPECT_EQ (s.size (), size_t (0));
  EXPECT_EQ (s.capacity (), size_t (0));

  // ...

}

TEST(5)
{
  Extractor x ("\t5   :  -6 oder-1.5e001");
  Extractor xx ("\t   ");

  EXPECT_EQ (x.at_end (), false);
  EXPECT_EQ (xx.at_end (), true);

  unsigned int ui = 0;
  long l = 0;
  std::string s;
  double d = 0;

  x.read (ui);
  EXPECT_EQ (x.test (":"), true);
  x.read (l);
  x.read (s, "-");
  x.read (d);

  EXPECT_EQ (ui, (unsigned int) 5);
  EXPECT_EQ (l, -6);
  EXPECT_EQ (s, "oder");
  EXPECT_EQ (d, -15.0);
}

TEST(6)
{
  Extractor x ("\t5:  -6 oder");

  EXPECT_EQ (x.at_end (), false);

  unsigned long ul = 0;
  int i = 0;
  std::string s;

  EXPECT_EQ (x.try_read (ul), true);
  EXPECT_EQ (x.try_read (ul), false);
  EXPECT_EQ (ul, (unsigned long) 5);
  EXPECT_EQ (x.test (";"), false);
  x.expect (":");
  EXPECT_EQ (x.try_read (i), true);
  x.skip ();
  EXPECT_EQ (*x, 'o');
  ++x;
  EXPECT_EQ (x.try_read (s, "-"), true);
  EXPECT_EQ (s, "der");

  Extractor x1 ("\t aber:");
  x1.read (s, ":");
  EXPECT_EQ (s, "aber");

  Extractor x2 ("\t aber  :");
  x2.read (s);
  EXPECT_EQ (s, "aber");
  x2.expect (":");

  Extractor x3 ("\t aber\t:");
  x3.read (s);
  EXPECT_EQ (s, "aber");
  EXPECT_EQ (x3.test (";"), false);
  EXPECT_EQ (x3.test (":"), true);
}

TEST(6_double)
{
  Extractor x ("  5.5 -2.5 \n+0.125  (no number)");

  EXPECT_EQ (x.at_end (), false);

  double d = 0.0;

  EXPECT_EQ (x.try_read (d), true);
  EXPECT_EQ (d, 5.5);

  x.read (d);
  EXPECT_EQ (d, -2.5);
  x.read (d);
  EXPECT_EQ (d, 0.125);

  x.expect ("(");
}

TEST(7)
{
  EXPECT_EQ (tl::to_quoted_string ("a_word!"), "'a_word!'");
  EXPECT_EQ (tl::to_quoted_string ("a_word'!"), "'a_word\\'!'");
  EXPECT_EQ (tl::to_word_or_quoted_string ("a_word!"), "'a_word!'");
  EXPECT_EQ (tl::to_word_or_quoted_string ("a_word!", "_!"), "a_word!");
}

TEST(8)
{
  std::string s;
  Extractor x;

  x = Extractor ("a_word!");
  x.read_word (s);
  EXPECT_EQ (s, "a_word");

  x = Extractor ("a_word!");
  s.clear ();
  x.read_name (s);
  EXPECT_EQ (s, "a_word");
  EXPECT_EQ (x.test ("!"), true);

  x = Extractor ("0_word!");
  EXPECT_EQ (x.try_read_word (s), true);

  x = Extractor ("0_word!");
  EXPECT_EQ (x.try_read_name (s), false);

  x = Extractor ("a_word!");
  EXPECT_EQ (x.try_read_word (s), true);
  EXPECT_EQ (s, "a_word");
  EXPECT_EQ (x.test ("!"), true);

  x = Extractor ("a_word!");
  EXPECT_EQ (x.try_read_name (s), true);
  EXPECT_EQ (s, "a_word");
  EXPECT_EQ (x.test ("!"), true);

  x = Extractor ("a_word!");
  x.read_word (s, "_!");
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("a_word!");
  x.read_name (s, "_!");
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("a_word!");
  EXPECT_EQ (x.try_read_word (s, "_!"), true);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("a_word!");
  EXPECT_EQ (x.try_read_name (s, "_!"), true);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("a_word!");
  x.read_word_or_quoted (s);
  EXPECT_EQ (s, "a_word");
  EXPECT_EQ (x.test ("!"), true);

  x = Extractor ("a_word!");
  EXPECT_EQ (x.try_read_word_or_quoted (s), true);
  EXPECT_EQ (s, "a_word");
  EXPECT_EQ (x.test ("!"), true);

  x = Extractor ("a_word!");
  x.read_word_or_quoted (s, "_!");
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("a_word!");
  EXPECT_EQ (x.try_read_word_or_quoted (s, "_!"), true);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("'a_word!'");
  x.read_word_or_quoted (s);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("'a_word!'");
  EXPECT_EQ (x.try_read_word_or_quoted (s), true);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("'a_word!'x");
  EXPECT_EQ (x.try_read_word_or_quoted (s), true);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.test ("x"), true);

  x = Extractor ("'a_word\\'!'");
  EXPECT_EQ (x.try_read_word_or_quoted (s), true);
  EXPECT_EQ (s, "a_word\'!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("'a_word!'");
  x.read_quoted (s);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("'a_word!'");
  EXPECT_EQ (x.try_read_quoted (s), true);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor ("'a_word!'x");
  EXPECT_EQ (x.try_read_quoted (s), true);
  EXPECT_EQ (s, "a_word!");
  EXPECT_EQ (x.test ("x"), true);

  x = Extractor ("'a_word\\'!'");
  EXPECT_EQ (x.try_read_quoted (s), true);
  EXPECT_EQ (s, "a_word\'!");
  EXPECT_EQ (x.at_end (), true);

  x = Extractor (" foobar");
  EXPECT_EQ (x.test ("foo"), true);
  EXPECT_EQ (x.test ("bar"), true);

  x = Extractor (" foo bar");
  EXPECT_EQ (x.test ("foo"), true);
  EXPECT_EQ (x.test ("bar"), true);

  x = Extractor (" FOObar");
  EXPECT_EQ (x.test ("foo"), false);
  EXPECT_EQ (x.test ("BAR"), false);

  x = Extractor (" FOObar");
  EXPECT_EQ (x.test_without_case ("foo"), true);
  EXPECT_EQ (x.test_without_case ("BAR"), true);

  x = Extractor (" µm");
  EXPECT_EQ (x.test ("µm"), true);

  x = Extractor (" µM");
  EXPECT_EQ (x.test ("µm"), false);
  EXPECT_EQ (x.test_without_case ("µm"), true);

  x = Extractor (" µm");
  EXPECT_EQ (x.test ("µM"), false);
  EXPECT_EQ (x.test_without_case ("µM"), true);
}

TEST(9)
{
  EXPECT_EQ (tl::edit_distance ("", ""), 0);
  EXPECT_EQ (tl::edit_distance ("aber", "aber"), 0);
  EXPECT_EQ (tl::edit_distance ("ober", "aber"), 1);
  EXPECT_EQ (tl::edit_distance ("obe", "aber"), 2);
  EXPECT_EQ (tl::edit_distance ("abe", "aber"), 1);
  EXPECT_EQ (tl::edit_distance ("axbe", "aber"), 2);
  EXPECT_EQ (tl::edit_distance ("axbep", "aber"), 2);
  EXPECT_EQ (tl::edit_distance ("Tor", "Tier"), 2);
  EXPECT_EQ (tl::edit_distance ("kitten", "sitting"), 3);
  EXPECT_EQ (tl::edit_distance ("matthias", "koefferlein"), 11);
}

TEST(10)
{
  std::string s;
  s = to_quoted_string ("'a\n\003");
  EXPECT_EQ (s, "'\\'a\\n\\003'");
  std::string t;
  tl::Extractor ex (s.c_str ());
  ex.read_word_or_quoted (t);

  s = to_quoted_string ("hallo\303\t\r\"");
  EXPECT_EQ (s, "'hallo\\303\\t\\r\"'");
  t.clear ();
  ex = tl::Extractor (s.c_str ());
  ex.read_word_or_quoted (t);
  EXPECT_EQ (t, "hallo\303\t\r\"");

  EXPECT_EQ (escape_string ("'a\n\003"), "'a\\n\\003");
  EXPECT_EQ (escape_string ("'a\n\003"), "'a\\n\\003");
  EXPECT_EQ (unescape_string (escape_string ("'a\n\003")), "'a\n\003");
}

TEST(11)
{
  std::string s;
  tl::escape_to_html (s, "x");
  EXPECT_EQ (s, "x");
  tl::escape_to_html (s, "<&>");
  EXPECT_EQ (s, "x&lt;&amp;&gt;");
  s = std::string ();
  tl::escape_to_html (s, "a\nb");
  EXPECT_EQ (s, "a<br/>b");
  s = std::string ();
  tl::escape_to_html (s, "a\nb", false);
  EXPECT_EQ (s, "a\nb");
  EXPECT_EQ (tl::escaped_to_html ("x<&>\""), "x&lt;&amp;&gt;&quot;");
  EXPECT_EQ (tl::escaped_to_html ("a\nb"), "a<br/>b");
  EXPECT_EQ (tl::escaped_to_html ("a\nb", false), "a\nb");
}

TEST(12)
{
  EXPECT_EQ (replaced ("abc", "b", "xy"), "axyc");
  EXPECT_EQ (replaced ("ab", "b", "xy"), "axy");
  EXPECT_EQ (replaced ("bc", "b", "xy"), "xyc");
  EXPECT_EQ (replaced ("b", "b", "xy"), "xy");
  EXPECT_EQ (replaced ("bbbb", "b", "xy"), "xyxyxyxy");
  EXPECT_EQ (replaced ("", "b", "xy"), "");
  EXPECT_EQ (replaced ("ac", "b", "xy"), "ac");
  EXPECT_EQ (replaced ("abc", "b", ""), "ac");
  EXPECT_EQ (replaced ("bb", "b", ""), "");
  EXPECT_EQ (replaced ("bb", "bbb", ""), "bb");
  EXPECT_EQ (replaced ("abbbc", "bbb", "xy"), "axyc");
  EXPECT_EQ (replaced ("abbbbbbc", "bbb", "xy"), "axyxyc");
  EXPECT_EQ (replaced ("abbbbbbbc", "bbb", "xy"), "axyxybc");
}

TEST(13)
{
  EXPECT_EQ (replicate ("abc", 0), "");
  EXPECT_EQ (replicate ("abc", 1), "abc");
  EXPECT_EQ (replicate ("abc", 2), "abcabc");
  EXPECT_EQ (replicate ("", 2), "");
}

TEST(14)
{
  EXPECT_EQ (pad_string_right (0, "abc"), "abc");
  EXPECT_EQ (pad_string_right (2, "abc"), "abc");
  EXPECT_EQ (pad_string_right (4, "abc"), "abc ");
  EXPECT_EQ (pad_string_right (6, "abc"), "abc   ");
  EXPECT_EQ (pad_string_right (4, ""), "    ");
  EXPECT_EQ (pad_string_left (0, "abc"), "abc");
  EXPECT_EQ (pad_string_left (2, "abc"), "abc");
  EXPECT_EQ (pad_string_left (4, "abc"), " abc");
  EXPECT_EQ (pad_string_left (6, "abc"), "   abc");
  EXPECT_EQ (pad_string_left (4, ""), "    ");
}

//  UTF-8 to wchar_t and local conversion
TEST(15)
{
  std::string locale = setlocale (LC_ALL, NULL);
  const char *lc = setlocale (LC_ALL, "en_US.UTF-8");
  if (! lc || std::string (lc) != "en_US.UTF-8") {
    //  use C.UTF-8 as fallback
    setlocale (LC_ALL, "C.UTF-8");
  }

  try {
    EXPECT_EQ (tl::to_string_from_local (tl::to_local ("H\xc3\xa4llo\tW\xc3\xb6rld!").c_str ()), "H\xc3\xa4llo\tW\xc3\xb6rld!");
    setlocale (LC_ALL, locale.c_str ());
  } catch (...) {
    setlocale (LC_ALL, locale.c_str ());
    throw;
  }

  EXPECT_EQ (std::string ("\xc3\x84").size (), size_t (2));
  EXPECT_EQ (tl::to_string (std::wstring (L"Ä")), "\xc3\x84");
  EXPECT_EQ (tl::to_wstring (std::string ("\xc3\x84")).size (), size_t (1));
  EXPECT_EQ (tl::to_string (tl::to_wstring ("Utf8 supports emoticons: \xF0\x9F\x98\x81\nand Umlauts: \xc3\xa4\xc3\xbc\xc3\xb6")).c_str (), "Utf8 supports emoticons: \xF0\x9F\x98\x81\nand Umlauts: \xc3\xa4\xc3\xbc\xc3\xb6");

  EXPECT_EQ (tl::to_upper_case ("nOrMaliI(\xc3\xa4\xc3\x84\xc3\xbc\xc3\x9c\xc3\xb6\xc3\x96\xc3\x9f-42\xc2\xb0+6\xe2\x82\xac)"), "NORMALII(\xc3\x84\xc3\x84\xc3\x9c\xc3\x9c\xc3\x96\xc3\x96\xc3\x9f-42\xc2\xb0+6\xe2\x82\xac)");
  EXPECT_EQ (tl::to_lower_case ("nOrMaliI(\xc3\xa4\xc3\x84\xc3\xbc\xc3\x9c\xc3\xb6\xc3\x96\xc3\x9f-42\xc2\xb0+6\xe2\x82\xac)"), "normalii(\xc3\xa4\xc3\xa4\xc3\xbc\xc3\xbc\xc3\xb6\xc3\xb6\xc3\x9f-42\xc2\xb0+6\xe2\x82\xac)");
}

//  Special numerical values
TEST(16)
{
  EXPECT_EQ (tl::to_string (NAN), "nan");
  EXPECT_EQ (tl::to_string (INFINITY), "inf");
  EXPECT_EQ (tl::to_string (-INFINITY), "-inf");

  EXPECT_EQ (tl::to_string ((float) NAN), "nan");
  EXPECT_EQ (tl::to_string ((float) INFINITY), "inf");
  EXPECT_EQ (tl::to_string ((float) -INFINITY), "-inf");

  EXPECT_EQ (tl::micron_to_string (NAN), "nan");
  EXPECT_EQ (tl::micron_to_string (INFINITY), "inf");
  EXPECT_EQ (tl::micron_to_string (-INFINITY), "-inf");

  EXPECT_EQ (tl::db_to_string (NAN), "nan");
  EXPECT_EQ (tl::db_to_string (INFINITY), "inf");
  EXPECT_EQ (tl::db_to_string (-INFINITY), "-inf");

  double x = 0.0;
  tl::from_string ("nan", x);
  EXPECT_EQ (tl::to_string (x), "nan");
  x = 0.0;
  tl::from_string ("NaN", x);
  EXPECT_EQ (tl::to_string (x), "nan");
  x = 0.0;
  tl::from_string ("inf", x);
  EXPECT_EQ (tl::to_string (x), "inf");
  x = 0.0;
  tl::from_string ("INF", x);
  EXPECT_EQ (tl::to_string (x), "inf");
  x = 0.0;
  tl::from_string ("-inf", x);
  EXPECT_EQ (tl::to_string (x), "-inf");
  x = 0.0;
  tl::from_string ("-INF", x);
  EXPECT_EQ (tl::to_string (x), "-inf");

  std::string s;
  tl::Extractor ex;
  x = 0.0;
  s = "  inf   nan\t -inf";
  ex = tl::Extractor (s.c_str ());
  EXPECT_EQ (ex.try_read (x), true);
  EXPECT_EQ (tl::to_string (x), "inf");
  EXPECT_EQ (ex.try_read (x), true);
  EXPECT_EQ (tl::to_string (x), "nan");
  EXPECT_EQ (ex.try_read (x), true);
  EXPECT_EQ (tl::to_string (x), "-inf");
  s = "  Inf   NaN\t -INF";
  ex = tl::Extractor (s.c_str ());
  EXPECT_EQ (ex.try_read (x), true);
  EXPECT_EQ (tl::to_string (x), "inf");
  EXPECT_EQ (ex.try_read (x), true);
  EXPECT_EQ (tl::to_string (x), "nan");
  EXPECT_EQ (ex.try_read (x), true);
  EXPECT_EQ (tl::to_string (x), "-inf");
}
