
/*

  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 "layParsedLayerSource.h"
#include "dbLayout.h"
#include "dbCell.h"
#include "tlUnitTest.h"

TEST (1)
{
  lay::ParsedLayerSource ps1 (1, 2, -1);
  EXPECT_EQ (ps1.to_string (), "1/2@*");

  lay::ParsedLayerSource ps2 (5, 0, 0);
  EXPECT_EQ (ps2.to_string (), "5/0@1");
  EXPECT_EQ (ps2.has_name (), false);

  lay::ParsedLayerSource ps3 ("aname", 1);
  EXPECT_EQ (ps3.to_string (), "aname@2");
  EXPECT_EQ (ps3.has_name (), true);

  lay::ParsedLayerSource ps4 ("bname", -1);
  EXPECT_EQ (ps4.to_string (), "bname@*");

  EXPECT_EQ (ps1 < ps2, true);
  EXPECT_EQ (ps2 < ps2, false);
  EXPECT_EQ (ps2 < ps1, false);
  EXPECT_EQ (ps2 < ps3, true);
  EXPECT_EQ (ps3 < ps4, false);
  EXPECT_EQ (ps4 < ps3, true);

  EXPECT_EQ (ps1 == ps2, false);
  EXPECT_EQ (ps2 == ps3, false);
  EXPECT_EQ (ps3 == ps4, false);
  EXPECT_EQ (ps4 == lay::ParsedLayerSource ("x", -1), false);
  EXPECT_EQ (ps4 == lay::ParsedLayerSource ("bname", -1), true);
  EXPECT_EQ (ps3 == lay::ParsedLayerSource ("aname", 1), true);
  EXPECT_EQ (ps2 == lay::ParsedLayerSource (5, 0, 0), true);

  EXPECT_EQ (ps4 != lay::ParsedLayerSource ("x", -1), true);
  EXPECT_EQ (ps4 != lay::ParsedLayerSource ("bname", -1), false);

  EXPECT_EQ (ps1 == lay::ParsedLayerSource (ps1.to_string ()), true);
  EXPECT_EQ (ps2 == lay::ParsedLayerSource (ps2.to_string ()), true);
  EXPECT_EQ (ps3 == lay::ParsedLayerSource (ps3.to_string ()), true);
  EXPECT_EQ (ps4 == lay::ParsedLayerSource (ps4.to_string ()), true);

  ps1 = ps2;
  lay::ParsedLayerSource psc = ps2;
  EXPECT_EQ (ps1 == ps2, true);
  EXPECT_EQ (ps2 == psc, true);

  EXPECT_EQ (lay::ParsedLayerSource ("4/0@*") == lay::ParsedLayerSource (4, 0, -1), true);
}

TEST (2)
{
  lay::ParsedLayerSource ps1 ("@2");
  EXPECT_EQ (ps1.to_string (), "*/*@2");

  lay::ParsedLayerSource ps2 ("5");
  EXPECT_EQ (ps2.to_string (), "5/0@1");

  lay::ParsedLayerSource ps3 ("/5");
  EXPECT_EQ (ps3.to_string (), "*/5@1");

  lay::ParsedLayerSource ps4 ("name@5");
  EXPECT_EQ (ps4.to_string (), "name@5");

  lay::ParsedLayerSource ps5 ("name");
  EXPECT_EQ (ps5.to_string (), "name@1");

  lay::ParsedLayerSource ps6 ("%5");
  EXPECT_EQ (ps6.to_string (), "%5@1");

  lay::ParsedLayerSource ps7 ("1/5%4@7");
  EXPECT_EQ (ps7.to_string (), "%4@7");
}

TEST (3)
{
  lay::ParsedLayerSource ps1 ("@2");
  ps1 += lay::ParsedLayerSource ("1");
  EXPECT_EQ (ps1.to_string (), "1/0@2");

  lay::ParsedLayerSource ps2 ("@2");
  ps2 += lay::ParsedLayerSource ("@3");
  EXPECT_EQ (ps2.to_string (), "*/*@2");

  lay::ParsedLayerSource ps3 ("1/5@*");
  ps3 += lay::ParsedLayerSource ("@3");
  EXPECT_EQ (ps3.to_string (), "1/5@3");

  lay::ParsedLayerSource ps4 ("namea");
  EXPECT_EQ (ps4.has_name (), true);
  ps4 += lay::ParsedLayerSource ("nameb");
  EXPECT_EQ (ps4.has_name (), true);
  EXPECT_EQ (ps4.to_string (), "namea@1");

  lay::ParsedLayerSource ps5 ("namea@5");
  ps5 += lay::ParsedLayerSource ("1/*");
  EXPECT_EQ (ps5.to_string (), "namea 1/*@5");

  lay::ParsedLayerSource ps6 ("1/5@4");
  EXPECT_EQ (ps6.has_name (), false);
  ps6 += lay::ParsedLayerSource ("nameb");
  EXPECT_EQ (ps6.has_name (), true);
  EXPECT_EQ (ps6.to_string (), "nameb 1/5@4");

  lay::ParsedLayerSource ps7 ("*/5");
  EXPECT_EQ (ps7.has_name (), false);
  ps7 += lay::ParsedLayerSource ("2/7");
  EXPECT_EQ (ps7.has_name (), false);
  EXPECT_EQ (ps7.to_string (), "2/5@1");

  lay::ParsedLayerSource ps8 ("1/*@1");
  ps8 += lay::ParsedLayerSource ("*/8@2");
  EXPECT_EQ (ps8.to_string (), "1/8@1");

  lay::ParsedLayerSource ps9;
  EXPECT_EQ (ps9.to_string (), "*/*@*");
  EXPECT_EQ (ps9.has_name (), false);
  ps9.layer (2);
  EXPECT_EQ (ps9.to_string (), "2/*@*");
  EXPECT_EQ (ps9.has_name (), false);
  ps9.datatype (3);
  EXPECT_EQ (ps9.to_string (), "2/3@*");
  EXPECT_EQ (ps9.has_name (), false);
  ps9.name ("abc");
  EXPECT_EQ (ps9.to_string (), "abc 2/3@*");
  EXPECT_EQ (ps9.has_name (), true);
  ps9.name (std::string ());
  EXPECT_EQ (ps9.to_string (), "2/3@*");
  EXPECT_EQ (ps9.has_name (), false);
}

TEST (4)
{
  lay::ParsedLayerSource ps1 ("@2");
  EXPECT_EQ (ps1.to_string (), "*/*@2");

  lay::ParsedLayerSource ps2 ("@2 (*0.5 -1.0,17.1 m45)");
  EXPECT_EQ (ps2.to_string (), "*/*@2 (m45 *0.5 -1,17.1)");
}

TEST (5)
{
  lay::ParsedLayerSource ps0 ("@2");

  lay::ParsedLayerSource ps1 ("@2 [ X   == #2 ]");
  EXPECT_EQ (ps1.to_string (), "*/*@2 ['X'==#2]");

  lay::ParsedLayerSource ps2 ("[X==#2||X==Y&&Z!=##4] @2");
  EXPECT_EQ (ps2.to_string (), "*/*@2 [('X'==#2||'X'=='Y')&&'Z'!=##4]");

  lay::ParsedLayerSource ps2a ("[!(X==#2||X==Y&&Z!=##4)] @2");
  EXPECT_EQ (ps2a.to_string (), "*/*@2 [!(('X'==#2||'X'=='Y')&&'Z'!=##4)]");

  lay::ParsedLayerSource ps2b ("[(X!=#2&&X!=Y)||Z==##4] @2");
  EXPECT_EQ (ps2b.to_string (), "*/*@2 [('X'!=#2&&'X'!='Y')||'Z'==##4]");

  lay::ParsedLayerSource ps3 ("[!(X==#2||(X==Y&&Y==X)&&!Z!=##4)] @2");
  EXPECT_EQ (ps3.to_string (), "*/*@2 [!(('X'==#2||('X'=='Y'&&'Y'=='X'))&&!('Z'!=##4))]");

  lay::ParsedLayerSource ps4 ("@2 [X==#2||X==#3||X==#20||X==#120||X==#210||X==#5||X==#15||X==#11||X==#17||X==#18]");
  EXPECT_EQ (ps4.to_string (), "*/*@2 ['X'==#2||'X'==#3||'X'==#20||'X'==#120||'X'==#210||'X'==#5||'X'==#15||'X'==#11||'X'==#17||'X'==#18]");
  EXPECT_EQ (ps4.display_string (0), "@2 ['X'==#2||'X'==#3||'X'==#20||'X'==#120||...]");

  lay::ParsedLayerSource ps4a;
  ps4a = ps4;
  EXPECT_EQ (ps4a.to_string (), ps4.to_string ());
  EXPECT_EQ (ps4a == ps4, true);

  lay::ParsedLayerSource ps4b (ps4);
  EXPECT_EQ (ps4b.to_string (), ps4.to_string ());

  lay::ParsedLayerSource ps4c ("@2 [X==#3||X==#20||X==#120||X==#210||X==#5||X==#15||X==#11||X==#17||X==#18]");
  EXPECT_EQ (ps4c == ps4, false);
  EXPECT_EQ (ps4c < ps4, true);
  EXPECT_EQ (ps4 < ps4c, false);

  lay::ParsedLayerSource ps4d ("@2 [X==#2||X==#4||X==#20||X==#120||X==#210||X==#5||X==#15||X==#11||X==#17||X==#18]");
  EXPECT_EQ (ps4d == ps4, false);
  EXPECT_EQ (ps4d < ps4, false);
  EXPECT_EQ (ps4 < ps4d, true);

  lay::ParsedLayerSource ps4e ("@2 [X==##2||X==#3||X==#20||X==#120||X==#210||X==#5||X==#15||X==#11||X==#17||X==#18]");
  EXPECT_EQ (ps4e == ps4, true);
  EXPECT_EQ (ps4e < ps4, false);
  EXPECT_EQ (ps4 < ps4e, false);

  lay::ParsedLayerSource ps4f ("@2 [X==#222||X==#3||X==#4||X==#20||X==#120||X==#210||X==#5||X==#15||X==#11||X==#17||X==#18]");
  EXPECT_EQ (ps4f == ps4, false);
  EXPECT_EQ (ps4f < ps4, false);
  EXPECT_EQ (ps4 < ps4f, true);

  lay::ParsedLayerSource ps4g ("@2 [X!=#2||X==#3||X==#20||X==#120||X==#210||X==#5||X==#15||X==#11||X==#17||X==#18]");
  EXPECT_EQ (ps4g == ps4, false);
  EXPECT_EQ (ps4g < ps4, false);
  EXPECT_EQ (ps4 < ps4g, true);

  db::PropertiesRepository::properties_set ps;
  db::PropertiesRepository rep;
  std::set<db::properties_id_type> ids;
  bool inv;

  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("X")), tl::Variant (2l)));
  db::properties_id_type id1 = rep.properties_id (ps);
  EXPECT_EQ (ps1.property_selector ().check (rep, id1), true);
  EXPECT_EQ (ps0.property_selector ().check (rep, id1), true);
  ids.clear ();
  inv = ps1.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, false);
  EXPECT_EQ (ids.size (), size_t (1));
  EXPECT_EQ (*ids.begin (), id1);
  ids.clear ();
  inv = ps0.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, true);
  EXPECT_EQ (ids.size (), size_t (0));
  ps.clear ();

  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("X")), tl::Variant (3l)));
  db::properties_id_type id2 = rep.properties_id (ps);
  EXPECT_EQ (ps1.property_selector ().check (rep, id2), false);
  EXPECT_EQ (ps0.property_selector ().check (rep, id2), true);
  ids.clear ();
  inv = ps1.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, false);
  EXPECT_EQ (ids.size (), size_t (1));
  EXPECT_EQ (*ids.begin () == id2, false);
  EXPECT_EQ (*ids.begin (), id1);
  ids.clear ();
  inv = ps0.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, true);
  EXPECT_EQ (ids.size (), size_t (0));
  ps.clear ();

  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("X")), tl::Variant (2l)));
  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("Z")), tl::Variant (4.0)));
  db::properties_id_type id3 = rep.properties_id (ps);
  EXPECT_EQ (ps2.property_selector ().check (rep, id3), false);
  EXPECT_EQ (ps0.property_selector ().check (rep, id3), true);
  ids.clear ();
  inv = ps2.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, false);
  EXPECT_EQ (ids.size (), size_t (1));
  EXPECT_EQ (*ids.begin () == id3, false);
  EXPECT_EQ (*ids.begin (), id1);
  ids.clear ();
  inv = ps0.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, true);
  EXPECT_EQ (ids.size (), size_t (0));
  ps.clear ();

  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("X")), tl::Variant (2l)));
  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("Z")), tl::Variant (6l)));
  db::properties_id_type id4 = rep.properties_id (ps);
  EXPECT_EQ (ps2.property_selector ().check (rep, id4), true);
  ids.clear ();
  inv = ps2.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, false);
  EXPECT_EQ (ids.size (), size_t (2));
  EXPECT_EQ (*ids.begin (), id1);
  EXPECT_EQ (*(++ids.begin ()), id4);
  ps.clear ();

  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("X")), tl::Variant (2l)));
  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("Z")), tl::Variant (5.0)));
  db::properties_id_type id5 = rep.properties_id (ps);
  EXPECT_EQ (ps2.property_selector ().check (rep, id5), true);
  ids.clear ();
  inv = ps2.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, false);
  EXPECT_EQ (ids.size (), size_t (3));
  EXPECT_EQ (*ids.begin (), id1);
  EXPECT_EQ (*(++ids.begin ()), id4);
  EXPECT_EQ (*(++(++ids.begin ())), id5);

  EXPECT_EQ (ps2a.property_selector ().check (rep, id5), false);
  ids.clear ();
  inv = ps2a.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, true);
  EXPECT_EQ (ids.size (), size_t (3));
  EXPECT_EQ (*ids.begin (), id1);
  EXPECT_EQ (*(++ids.begin ()), id4);
  EXPECT_EQ (*(++(++ids.begin ())), id5);

  EXPECT_EQ (ps2b.property_selector ().check (rep, id5), false);
  ids.clear ();
  inv = ps2b.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, true);
  EXPECT_EQ (ids.size (), size_t (3));
  EXPECT_EQ (*ids.begin (), id1);
  EXPECT_EQ (*(++ids.begin ()), id4);
  EXPECT_EQ (*(++(++ids.begin ())), id5);

  ps.clear ();

  db::properties_id_type id6 = rep.properties_id (ps);
  EXPECT_EQ (ps2.property_selector ().check (rep, id6), false);
  ids.clear ();
  inv = ps2.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, false);
  EXPECT_EQ (ids.size (), size_t (3));
  EXPECT_EQ (*ids.begin (), id1);
  EXPECT_EQ (*(++ids.begin ()), id4);
  EXPECT_EQ (*(++(++ids.begin ())), id5);

  EXPECT_EQ (ps0.property_selector ().check (rep, id6), true);
  ids.clear ();
  inv = ps0.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, true);
  EXPECT_EQ (ids.size (), size_t (0));

  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("Z")), tl::Variant (5l)));
  db::properties_id_type id7 = rep.properties_id (ps);
  EXPECT_EQ (ps4.property_selector ().check (rep, id7), false);
  ids.clear ();
  inv = ps4.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, false);
  EXPECT_EQ (ids.size (), size_t (5));
  EXPECT_EQ (ids.find (id7) == ids.end (), true);

  ps.insert (std::make_pair (rep.prop_name_id (tl::Variant ("X")), tl::Variant (15l)));
  db::properties_id_type id8 = rep.properties_id (ps);
  EXPECT_EQ (ps4.property_selector ().check (rep, id8), true);
  ids.clear ();
  inv = ps4.property_selector ().matching (rep, ids);
  EXPECT_EQ (inv, false);
  EXPECT_EQ (ids.size (), size_t (6));
  EXPECT_EQ (ids.find (id8) != ids.end (), true);
}

TEST (6)
{
  lay::ParsedLayerSource ps1;

  ps1 = lay::ParsedLayerSource ("");
  EXPECT_EQ (ps1.to_string (), "*/*@1");

  ps1 = lay::ParsedLayerSource ("#1");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #0..1");

  ps1 = lay::ParsedLayerSource ("#1..4");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #1..4");
  EXPECT_EQ (ps1 == lay::ParsedLayerSource ("#1..4"), true);
  EXPECT_EQ (ps1 != lay::ParsedLayerSource ("#1..4"), false);
  EXPECT_EQ (ps1 == lay::ParsedLayerSource ("#1..5"), false);
  EXPECT_EQ (ps1 != lay::ParsedLayerSource ("#1..5"), true);

  ps1 = lay::ParsedLayerSource ("#1..2");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #1..2");

  ps1 = lay::ParsedLayerSource ("   #   ..   2");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #..2");

  ps1 = lay::ParsedLayerSource (" #   1 ..   ");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #1..");

  ps1 = lay::ParsedLayerSource ();
  ps1 += lay::ParsedLayerSource ("#..20");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #..20");

  ps1 += lay::ParsedLayerSource ("#10..11");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #10..20");

  ps1 = lay::ParsedLayerSource ();
  ps1 += lay::ParsedLayerSource ("#5..");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #5..");

  ps1 += lay::ParsedLayerSource ("#10..11");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #5..11");

  ps1 = lay::ParsedLayerSource ("#*");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #0..*");

  ps1 = lay::ParsedLayerSource ("#..*");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #..*");

  ps1 = lay::ParsedLayerSource ("#..(*)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #..*");

  ps1 = lay::ParsedLayerSource ("#1..*");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #1..*");

  ps1 = lay::ParsedLayerSource ("#1..(*)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #1..*");

  ps1 = lay::ParsedLayerSource ("#(*)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #(0)..*");

  ps1 = lay::ParsedLayerSource ("#(-1)..(5)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #(-1)..(5)");

  ps1 = lay::ParsedLayerSource ("#(2)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #(0)..(2)");

  ps1 = lay::ParsedLayerSource ("#(2)..3");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #(2)..3");

  ps1 = lay::ParsedLayerSource ("#2..(3)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #2..(3)");

  ps1 = lay::ParsedLayerSource ("#>2..(<3)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #>2..(<3)");

  ps1 = lay::ParsedLayerSource ("#>2..(<*)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 #>2..<*");
}

TEST (7)
{
  lay::ParsedLayerSource ps1;
  ps1 = lay::ParsedLayerSource ("(*2)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 (r0 *2 0,0)");
  ps1 = lay::ParsedLayerSource ("(*2) (*1.5)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 (r0 *2 0,0) (r0 *1.5 0,0)");

  lay::ParsedLayerSource ps2 (ps1);
  ps1 += lay::ParsedLayerSource ("(*2)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 (r0 *4 0,0) (r0 *3 0,0)");

  ps1 = ps2;
  ps1 += lay::ParsedLayerSource ("(*2) (*3)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 (r0 *4 0,0) (r0 *6 0,0) (r0 *3 0,0) (r0 *4.5 0,0)");
}

TEST (8)
{
  lay::ParsedLayerSource ps1;
  ps1 = lay::ParsedLayerSource ("(*2) {-* +HALLO}");
  EXPECT_EQ (ps1.to_string (), "*/*@1 {-* +HALLO} (r0 *2 0,0)");
  ps1 = lay::ParsedLayerSource ("{-HALLO} (*2) (*1.5)");
  EXPECT_EQ (ps1.to_string (), "*/*@1 {-HALLO} (r0 *2 0,0) (r0 *1.5 0,0)");
}

TEST (10)
{
  lay::CellSelector sel;

  tl::Extractor ex;

  ex = tl::Extractor ("+HALLO * -H*");
  sel.parse (ex);
  EXPECT_EQ (sel.to_string (), "+HALLO +* -H*");

  ex = tl::Extractor ("+HALLO * -H*}ignored");
  sel.parse (ex);
  EXPECT_EQ (sel.to_string (), "+HALLO +* -H*");
  EXPECT_EQ (ex.test ("}"), true);

  ex = tl::Extractor ("+HALLO (* -H*)");
  sel.parse (ex);
  EXPECT_EQ (sel.to_string (), "+HALLO (+* -H*)");

  ex = tl::Extractor ("( +HALLO -H* ) ( *HA 'WITH BLANK' )");
  sel.parse (ex);
  EXPECT_EQ (sel.to_string (), "(+HALLO -H*) (+*HA +'WITH BLANK')");

  std::string c = sel.to_string ();
  ex = tl::Extractor (c.c_str ());
  sel = lay::CellSelector ();
  sel.parse (ex);
  EXPECT_EQ (sel.to_string (), "(+HALLO -H*) (+*HA +'WITH BLANK')");

  lay::CellSelector sel2;
  EXPECT_EQ (sel2.to_string (), "");
  EXPECT_EQ (sel2.is_empty (), true);
  EXPECT_EQ (sel == sel2, false);
  EXPECT_EQ (sel != sel2, true);
  EXPECT_EQ (sel < sel2, false);
  EXPECT_EQ (sel2 < sel, true);

  sel2 = sel;
  EXPECT_EQ (sel2.to_string (), "(+HALLO -H*) (+*HA +'WITH BLANK')");
  EXPECT_EQ (sel2.is_empty (), false);
  EXPECT_EQ (sel == sel2, true);
  EXPECT_EQ (sel != sel2, false);
  EXPECT_EQ (sel < sel2, false);
  EXPECT_EQ (sel2 < sel, false);

  lay::CellSelector sel2a (sel2);
  EXPECT_EQ (sel2a.to_string (), "(+HALLO -H*) (+*HA +'WITH BLANK')");
}

lay::CellSelector selector_from_string (const char *s)
{
  tl::Extractor ex (s);
  lay::CellSelector sel;
  sel.parse (ex);
  return sel;
}

std::string tspath (const db::Layout &l, db::cell_index_type c, lay::PartialTreeSelector &pt)
{
  std::string r;
  if (pt.is_selected ()) {
    r += "+";
  } else {
    r += "-";
  }
  r += l.cell_name (c);

  bool any = false;

  for (db::Cell::child_cell_iterator cc = l.cell (c).begin_child_cells (); ! cc.at_end (); ++cc) {
    int cs = pt.is_child_selected (*cc);
    if (cs) {
      if (! any) {
        r += "(";
        any = true;
      }
      pt.descend (*cc);
      r += tspath (l, *cc, pt);
      pt.ascend ();
    }
  }

  if (any) {
    r += ")";
  }

  return r;
}

TEST (11)
{
  db::Layout layout;
  db::Cell &c1 = layout.cell (layout.add_cell ("C1"));
  db::Cell &c2 = layout.cell (layout.add_cell ("C2"));
  db::Cell &c3 = layout.cell (layout.add_cell ("C3"));
  db::Cell &c4 = layout.cell (layout.add_cell ("C4"));
  db::Cell &c5 = layout.cell (layout.add_cell ("C5"));
  db::Cell &cc1 = layout.cell (layout.add_cell ("CC1"));
  db::Cell &cc2 = layout.cell (layout.add_cell ("CC2"));
  db::Cell &cc3 = layout.cell (layout.add_cell ("CC3"));
  db::Cell &cc4 = layout.cell (layout.add_cell ("CC4"));
  
  c1.insert (db::CellInstArray (c2.cell_index (), db::Trans ()));
  c2.insert (db::CellInstArray (c3.cell_index (), db::Trans ()));
  c2.insert (db::CellInstArray (c4.cell_index (), db::Trans ()));
  c2.insert (db::CellInstArray (cc2.cell_index (), db::Trans ()));
  c4.insert (db::CellInstArray (cc4.cell_index (), db::Trans ()));
  c3.insert (db::CellInstArray (cc3.cell_index (), db::Trans ()));
  c3.insert (db::CellInstArray (c5.cell_index (), db::Trans ()));
  c1.insert (db::CellInstArray (cc1.cell_index (), db::Trans ()));

  lay::PartialTreeSelector pt (selector_from_string("").create_tree_selector (layout, c1.cell_index ()));
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "+C1(+C2(+C3(+C5+CC3)+C4(+CC4)+CC2)+CC1)");

  pt = selector_from_string("+C1").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "+C1(+C2(+C3(+C5+CC3)+C4(+CC4)+CC2)+CC1)");

  pt = selector_from_string("-C1").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "-C1");

  pt = selector_from_string("-C2").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "+C1(+CC1)");

  pt = selector_from_string("+C1 -C2").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "+C1(+CC1)");

  pt = selector_from_string("+C1 ( -C* +CC* )").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "+C1(+CC1)");

  pt = selector_from_string("-C2 +C3").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "+C1(-C2(+C3(+C5+CC3)-C4(-CC4)-CC2)+CC1)");

  pt = selector_from_string("-C2 +CC*").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "+C1(-C2(-C3(-C5+CC3)-C4(+CC4)+CC2)+CC1)");

  pt = selector_from_string("+CC*").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "-C1(-C2(-C3(-C5+CC3)-C4(+CC4)+CC2)+CC1)");

  pt = selector_from_string("-* +CC*").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "-C1(-C2(-C3(-C5+CC3)-C4(+CC4)+CC2)+CC1)");

  pt = selector_from_string("-* ( -* +CC* )").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "-C1(+CC1)");

  pt = selector_from_string("-C3 +CC*").create_tree_selector (layout, c1.cell_index ());
  EXPECT_EQ (tspath (layout, c1.cell_index (), pt), "+C1(+C2(-C3(-C5+CC3)+C4(+CC4)+CC2)+CC1)");
}

