From a9b64d1e577d1e3e84f95a4b61deb7fb1308df2b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Aug 2017 18:47:52 +0200 Subject: [PATCH] Refactoring and first bd tests The goal of the refactoring is to support unit tests for the db library. For this, a distributed unit test concept has been introduced (later to be extended to other libs). Unit tests are shared objects called ".ut" and are automatically loaded by the ut runner. The bd library now has two folders - one for sources and one for the unit tests. The sources are separated into lib and apps. First unit tests for the writer options have been provided. --- src/buddies/buddies.pro | 22 +- src/buddies/mkbuddies.sh | 18 -- src/buddies/{ => src}/bd/bd.pro | 8 +- src/buddies/{ => src}/bd/bdCommon.h | 0 src/buddies/{ => src}/bd/bdConverterMain.cc | 0 src/buddies/{ => src}/bd/bdConverterMain.h | 0 src/buddies/{ => src}/bd/bdInit.cc | 0 src/buddies/{ => src}/bd/bdInit.h | 0 src/buddies/{ => src}/bd/bdReaderOptions.cc | 0 src/buddies/{ => src}/bd/bdReaderOptions.h | 0 src/buddies/{ => src}/bd/bdWriterOptions.cc | 26 ++- src/buddies/{ => src}/bd/bdWriterOptions.h | 0 src/buddies/{ => src}/bd/main.cc | 0 src/buddies/{ => src}/bd/strm2cif.cc | 0 src/buddies/{ => src}/bd/strm2dxf.cc | 0 src/buddies/{ => src}/bd/strm2gds.cc | 0 src/buddies/{ => src}/bd/strm2gdstxt.cc | 0 src/buddies/{ => src}/bd/strm2oas.cc | 0 src/buddies/{ => src}/bd/strm2txt.cc | 0 src/buddies/{ => src}/bd/strmclip.cc | 0 src/buddies/{ => src}/bd/strmcmp.cc | 0 src/buddies/{ => src}/buddy_app.pri | 4 +- src/buddies/src/src.pro | 24 +++ src/buddies/{ => src}/strm2cif/strm2cif.pro | 0 src/buddies/{ => src}/strm2dxf/strm2dxf.pro | 0 src/buddies/{ => src}/strm2gds/strm2gds.pro | 0 .../{ => src}/strm2gdstxt/strm2gdstxt.pro | 0 src/buddies/{ => src}/strm2oas/strm2oas.pro | 0 src/buddies/{ => src}/strm2txt/strm2txt.pro | 0 src/buddies/{ => src}/strmclip/strmclip.pro | 0 src/buddies/{ => src}/strmcmp/strmcmp.pro | 0 src/buddies/{ => src}/strmxor/strmxor.cc | 0 src/buddies/src/strmxor/strmxor.pro | 13 ++ src/buddies/strmxor/strmxor.pro | 13 -- src/buddies/unit_tests/bdBasicTests.cc | 204 ++++++++++++++++++ src/buddies/unit_tests/unit_tests.pro | 13 ++ src/db/dbSaveLayoutOptions.h | 10 +- src/lib_ut.pri | 19 ++ src/plugins/plugin_ut.pri | 14 +- src/tl/tlCommandLineParser.cc | 78 +++++-- src/tl/tlCommandLineParser.h | 33 ++- src/ut/utMain.cc | 14 +- 42 files changed, 399 insertions(+), 114 deletions(-) delete mode 100644 src/buddies/mkbuddies.sh rename src/buddies/{ => src}/bd/bd.pro (70%) rename src/buddies/{ => src}/bd/bdCommon.h (100%) rename src/buddies/{ => src}/bd/bdConverterMain.cc (100%) rename src/buddies/{ => src}/bd/bdConverterMain.h (100%) rename src/buddies/{ => src}/bd/bdInit.cc (100%) rename src/buddies/{ => src}/bd/bdInit.h (100%) rename src/buddies/{ => src}/bd/bdReaderOptions.cc (100%) rename src/buddies/{ => src}/bd/bdReaderOptions.h (100%) rename src/buddies/{ => src}/bd/bdWriterOptions.cc (93%) rename src/buddies/{ => src}/bd/bdWriterOptions.h (100%) rename src/buddies/{ => src}/bd/main.cc (100%) rename src/buddies/{ => src}/bd/strm2cif.cc (100%) rename src/buddies/{ => src}/bd/strm2dxf.cc (100%) rename src/buddies/{ => src}/bd/strm2gds.cc (100%) rename src/buddies/{ => src}/bd/strm2gdstxt.cc (100%) rename src/buddies/{ => src}/bd/strm2oas.cc (100%) rename src/buddies/{ => src}/bd/strm2txt.cc (100%) rename src/buddies/{ => src}/bd/strmclip.cc (100%) rename src/buddies/{ => src}/bd/strmcmp.cc (100%) rename src/buddies/{ => src}/buddy_app.pri (85%) create mode 100644 src/buddies/src/src.pro rename src/buddies/{ => src}/strm2cif/strm2cif.pro (100%) rename src/buddies/{ => src}/strm2dxf/strm2dxf.pro (100%) rename src/buddies/{ => src}/strm2gds/strm2gds.pro (100%) rename src/buddies/{ => src}/strm2gdstxt/strm2gdstxt.pro (100%) rename src/buddies/{ => src}/strm2oas/strm2oas.pro (100%) rename src/buddies/{ => src}/strm2txt/strm2txt.pro (100%) rename src/buddies/{ => src}/strmclip/strmclip.pro (100%) rename src/buddies/{ => src}/strmcmp/strmcmp.pro (100%) rename src/buddies/{ => src}/strmxor/strmxor.cc (100%) create mode 100644 src/buddies/src/strmxor/strmxor.pro delete mode 100644 src/buddies/strmxor/strmxor.pro create mode 100644 src/buddies/unit_tests/bdBasicTests.cc create mode 100644 src/buddies/unit_tests/unit_tests.pro create mode 100644 src/lib_ut.pri diff --git a/src/buddies/buddies.pro b/src/buddies/buddies.pro index 2dcaa2e9a..fe717b85f 100644 --- a/src/buddies/buddies.pro +++ b/src/buddies/buddies.pro @@ -1,24 +1,6 @@ TEMPLATE = subdirs +SUBDIRS = src unit_tests -SUBDIRS = \ - bd \ - strm2cif \ - strm2dxf \ - strm2gds \ - strm2gdstxt \ - strm2oas \ - strm2txt \ - strmclip \ - strmcmp \ - strmxor \ +unit_tests.depends += src -strm2cif.depends += bd -strm2dxf.depends += bd -strm2gds.depends += bd -strm2gdstxt.depends += bd -strm2oas.depends += bd -strm2txt.depends += bd -strmclip.depends += bd -strmcmp.depends += bd -strmxor.depends += bd diff --git a/src/buddies/mkbuddies.sh b/src/buddies/mkbuddies.sh deleted file mode 100644 index 86d4c265b..000000000 --- a/src/buddies/mkbuddies.sh +++ /dev/null @@ -1,18 +0,0 @@ - -for x in *.cc; do - xx=${x/.cc} - echo "" >$xx/$xx.pro - echo 'include($$PWD/../../klayout.pri)' >>$xx/$xx.pro - echo "" >>$xx/$xx.pro - echo "TEMPLATE = app" >>$xx/$xx.pro - echo "" >>$xx/$xx.pro - echo "TARGET = $xx" >>$xx/$xx.pro - echo 'DESTDIR = $$OUT_PWD/../..' >>$xx/$xx.pro - echo "" >> $xx/$xx.pro - echo "SOURCES = $x" >>$xx/$xx.pro - echo "" >> $xx/$xx.pro - echo "INCLUDEPATH += ../../tl ../../db ../../gsi" >> $xx/$xx.pro - echo "DEPENDPATH += ../../tl ../../db ../../gsi" >> $xx/$xx.pro - echo 'LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi' >> $xx/$xx.pro -done - diff --git a/src/buddies/bd/bd.pro b/src/buddies/src/bd/bd.pro similarity index 70% rename from src/buddies/bd/bd.pro rename to src/buddies/src/bd/bd.pro index a051b5505..25076cbf2 100644 --- a/src/buddies/bd/bd.pro +++ b/src/buddies/src/bd/bd.pro @@ -1,8 +1,8 @@ -DESTDIR = $$OUT_PWD/../.. +DESTDIR = $$OUT_PWD/../../.. TARGET = klayout_bd -include($$PWD/../../klayout.pri) +include($$PWD/../../../klayout.pri) DEFINES += MAKE_BD_LIBRARY @@ -31,7 +31,7 @@ HEADERS = \ RESOURCES = \ -INCLUDEPATH += ../../tl ../../db ../../gsi ../../version -DEPENDPATH += ../../tl ../../db ../../gsi ../../version +INCLUDEPATH += ../../../tl ../../../db ../../../gsi ../../../version +DEPENDPATH += ../../../tl ../../../db ../../../gsi ../../../version LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi diff --git a/src/buddies/bd/bdCommon.h b/src/buddies/src/bd/bdCommon.h similarity index 100% rename from src/buddies/bd/bdCommon.h rename to src/buddies/src/bd/bdCommon.h diff --git a/src/buddies/bd/bdConverterMain.cc b/src/buddies/src/bd/bdConverterMain.cc similarity index 100% rename from src/buddies/bd/bdConverterMain.cc rename to src/buddies/src/bd/bdConverterMain.cc diff --git a/src/buddies/bd/bdConverterMain.h b/src/buddies/src/bd/bdConverterMain.h similarity index 100% rename from src/buddies/bd/bdConverterMain.h rename to src/buddies/src/bd/bdConverterMain.h diff --git a/src/buddies/bd/bdInit.cc b/src/buddies/src/bd/bdInit.cc similarity index 100% rename from src/buddies/bd/bdInit.cc rename to src/buddies/src/bd/bdInit.cc diff --git a/src/buddies/bd/bdInit.h b/src/buddies/src/bd/bdInit.h similarity index 100% rename from src/buddies/bd/bdInit.h rename to src/buddies/src/bd/bdInit.h diff --git a/src/buddies/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc similarity index 100% rename from src/buddies/bd/bdReaderOptions.cc rename to src/buddies/src/bd/bdReaderOptions.cc diff --git a/src/buddies/bd/bdReaderOptions.h b/src/buddies/src/bd/bdReaderOptions.h similarity index 100% rename from src/buddies/bd/bdReaderOptions.h rename to src/buddies/src/bd/bdReaderOptions.h diff --git a/src/buddies/bd/bdWriterOptions.cc b/src/buddies/src/bd/bdWriterOptions.cc similarity index 93% rename from src/buddies/bd/bdWriterOptions.cc rename to src/buddies/src/bd/bdWriterOptions.cc index b8be30d07..0a97b2ebf 100644 --- a/src/buddies/bd/bdWriterOptions.cc +++ b/src/buddies/src/bd/bdWriterOptions.cc @@ -31,7 +31,7 @@ namespace bd GenericWriterOptions::GenericWriterOptions () : m_scale_factor (1.0), m_dbu (0.0), - m_dont_write_empty_cells (false), m_keep_instances (false), m_write_context_info (false) + m_dont_write_empty_cells (false), m_keep_instances (false), m_write_context_info (true) { // .. nothing yet .. } @@ -81,9 +81,11 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin if (format.empty () || format == gds2_format_name || format == gds2text_format_name || format == oasis_format_name) { cmd << tl::arg (group + - "#--write-context-info", &m_write_context_info, "Writes context information", - "Include context information for PCell instances and other information in a format-specific " - "way. The resulting layout may show unexpected features for other consumers." + "!#--no-context-info", &m_write_context_info, "Does not write context information", + "Context information is included to maintain PCell parameters and library connections. " + "This information is kept inside the layout files in a proprietary way. This option disables " + "this feature to maintain compatibility with other consumers of the file. If this option is " + "used, PCell parameters and library links are lost." ); } @@ -170,7 +172,8 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin cmd << tl::arg (group + "-ok|--compression-level=level", &m_oasis_writer_options.compression_level, "Specifies the OASIS compression level", "This level describes how hard the OASIS writer will try to compress the shapes " - "using shape arrays. Building shape arrays may take some time and requires some memory.\n" + "using shape arrays. Building shape arrays may take some time and requires some memory. " + "The default compression level is 2.\n" "* 0 - no shape array building\n" "* 1 - nearest neighbor shape array formation\n" "* 2++ - enhanced shape array search algorithm using 2nd and further neighbor distances as well\n" @@ -188,8 +191,8 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin ) << tl::arg (group + "#--write-std-properties", &m_oasis_writer_options.write_std_properties, "Writes some global standard properties", - "This is an integer describing what standard properties shall be written. 0 is \"none\" (the default), " - "1 means \"global standard properties such as S_TOP_CELL\" are produced. With 2 also per-cell bounding " + "This is an integer describing what standard properties shall be written. 0 is \"none\", " + "1 means \"global standard properties such as S_TOP_CELL\" are produced (the default). With 2 also per-cell bounding " "boxes are produced." ) << tl::arg (group + @@ -209,7 +212,7 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin cmd << tl::arg (group + "-op|--polygon-mode=mode", &m_dxf_writer_options.polygon_mode, "Specifies how to write polygons", "This option specifies how to write polygons:\n" - "* 0: create POLYLINE\n" + "* 0: create POLYLINE (default)\n" "* 1: create LWPOLYLINE\n" "* 2: decompose into SOLID\n" "* 3: create HATCH" @@ -255,7 +258,6 @@ static void get_selected_cells (tl::Extractor &ex, const db::Layout &layout, std bool without_children = ex.test ("("); std::string filter; ex.read_word_or_quoted (filter, "_-.*?{}$[]"); - if (without_children) { ex.expect (")"); } @@ -270,15 +272,17 @@ static void get_selected_cells (tl::Extractor &ex, const db::Layout &layout, std if (pat.match (layout.cell_name (c->cell_index ()))) { std::set cells; - cells.insert (c->cell_index ()); if (! without_children) { c->collect_called_cells (cells); } + cells.insert (c->cell_index ()); if (! remove) { selected.insert (cells.begin (), cells.end ()); } else { - selected.erase (cells.begin (), cells.end ()); + for (std::set::const_iterator c = cells.begin (); c != cells.end (); ++c) { + selected.erase (*c); + } } } diff --git a/src/buddies/bd/bdWriterOptions.h b/src/buddies/src/bd/bdWriterOptions.h similarity index 100% rename from src/buddies/bd/bdWriterOptions.h rename to src/buddies/src/bd/bdWriterOptions.h diff --git a/src/buddies/bd/main.cc b/src/buddies/src/bd/main.cc similarity index 100% rename from src/buddies/bd/main.cc rename to src/buddies/src/bd/main.cc diff --git a/src/buddies/bd/strm2cif.cc b/src/buddies/src/bd/strm2cif.cc similarity index 100% rename from src/buddies/bd/strm2cif.cc rename to src/buddies/src/bd/strm2cif.cc diff --git a/src/buddies/bd/strm2dxf.cc b/src/buddies/src/bd/strm2dxf.cc similarity index 100% rename from src/buddies/bd/strm2dxf.cc rename to src/buddies/src/bd/strm2dxf.cc diff --git a/src/buddies/bd/strm2gds.cc b/src/buddies/src/bd/strm2gds.cc similarity index 100% rename from src/buddies/bd/strm2gds.cc rename to src/buddies/src/bd/strm2gds.cc diff --git a/src/buddies/bd/strm2gdstxt.cc b/src/buddies/src/bd/strm2gdstxt.cc similarity index 100% rename from src/buddies/bd/strm2gdstxt.cc rename to src/buddies/src/bd/strm2gdstxt.cc diff --git a/src/buddies/bd/strm2oas.cc b/src/buddies/src/bd/strm2oas.cc similarity index 100% rename from src/buddies/bd/strm2oas.cc rename to src/buddies/src/bd/strm2oas.cc diff --git a/src/buddies/bd/strm2txt.cc b/src/buddies/src/bd/strm2txt.cc similarity index 100% rename from src/buddies/bd/strm2txt.cc rename to src/buddies/src/bd/strm2txt.cc diff --git a/src/buddies/bd/strmclip.cc b/src/buddies/src/bd/strmclip.cc similarity index 100% rename from src/buddies/bd/strmclip.cc rename to src/buddies/src/bd/strmclip.cc diff --git a/src/buddies/bd/strmcmp.cc b/src/buddies/src/bd/strmcmp.cc similarity index 100% rename from src/buddies/bd/strmcmp.cc rename to src/buddies/src/bd/strmcmp.cc diff --git a/src/buddies/buddy_app.pri b/src/buddies/src/buddy_app.pri similarity index 85% rename from src/buddies/buddy_app.pri rename to src/buddies/src/buddy_app.pri index 4b983c378..a5f31ade2 100644 --- a/src/buddies/buddy_app.pri +++ b/src/buddies/src/buddy_app.pri @@ -1,11 +1,11 @@ -include($$PWD/../klayout.pri) +include($$PWD/../../klayout.pri) TEMPLATE = app PRO_BASENAME = $$basename(_PRO_FILE_) TARGET = $$replace(PRO_BASENAME, ".pro", "") -DESTDIR = $$OUT_PWD/../.. +DESTDIR = $$OUT_PWD/../../.. # Since the main function is entirely unspecific, we can put it into a common # place - it's not part of the bd sources. diff --git a/src/buddies/src/src.pro b/src/buddies/src/src.pro new file mode 100644 index 000000000..2dcaa2e9a --- /dev/null +++ b/src/buddies/src/src.pro @@ -0,0 +1,24 @@ + +TEMPLATE = subdirs + +SUBDIRS = \ + bd \ + strm2cif \ + strm2dxf \ + strm2gds \ + strm2gdstxt \ + strm2oas \ + strm2txt \ + strmclip \ + strmcmp \ + strmxor \ + +strm2cif.depends += bd +strm2dxf.depends += bd +strm2gds.depends += bd +strm2gdstxt.depends += bd +strm2oas.depends += bd +strm2txt.depends += bd +strmclip.depends += bd +strmcmp.depends += bd +strmxor.depends += bd diff --git a/src/buddies/strm2cif/strm2cif.pro b/src/buddies/src/strm2cif/strm2cif.pro similarity index 100% rename from src/buddies/strm2cif/strm2cif.pro rename to src/buddies/src/strm2cif/strm2cif.pro diff --git a/src/buddies/strm2dxf/strm2dxf.pro b/src/buddies/src/strm2dxf/strm2dxf.pro similarity index 100% rename from src/buddies/strm2dxf/strm2dxf.pro rename to src/buddies/src/strm2dxf/strm2dxf.pro diff --git a/src/buddies/strm2gds/strm2gds.pro b/src/buddies/src/strm2gds/strm2gds.pro similarity index 100% rename from src/buddies/strm2gds/strm2gds.pro rename to src/buddies/src/strm2gds/strm2gds.pro diff --git a/src/buddies/strm2gdstxt/strm2gdstxt.pro b/src/buddies/src/strm2gdstxt/strm2gdstxt.pro similarity index 100% rename from src/buddies/strm2gdstxt/strm2gdstxt.pro rename to src/buddies/src/strm2gdstxt/strm2gdstxt.pro diff --git a/src/buddies/strm2oas/strm2oas.pro b/src/buddies/src/strm2oas/strm2oas.pro similarity index 100% rename from src/buddies/strm2oas/strm2oas.pro rename to src/buddies/src/strm2oas/strm2oas.pro diff --git a/src/buddies/strm2txt/strm2txt.pro b/src/buddies/src/strm2txt/strm2txt.pro similarity index 100% rename from src/buddies/strm2txt/strm2txt.pro rename to src/buddies/src/strm2txt/strm2txt.pro diff --git a/src/buddies/strmclip/strmclip.pro b/src/buddies/src/strmclip/strmclip.pro similarity index 100% rename from src/buddies/strmclip/strmclip.pro rename to src/buddies/src/strmclip/strmclip.pro diff --git a/src/buddies/strmcmp/strmcmp.pro b/src/buddies/src/strmcmp/strmcmp.pro similarity index 100% rename from src/buddies/strmcmp/strmcmp.pro rename to src/buddies/src/strmcmp/strmcmp.pro diff --git a/src/buddies/strmxor/strmxor.cc b/src/buddies/src/strmxor/strmxor.cc similarity index 100% rename from src/buddies/strmxor/strmxor.cc rename to src/buddies/src/strmxor/strmxor.cc diff --git a/src/buddies/src/strmxor/strmxor.pro b/src/buddies/src/strmxor/strmxor.pro new file mode 100644 index 000000000..0896bd247 --- /dev/null +++ b/src/buddies/src/strmxor/strmxor.pro @@ -0,0 +1,13 @@ + +include($$PWD/../../../klayout.pri) + +TEMPLATE = app + +TARGET = strmxor +DESTDIR = $$OUT_PWD/../../.. + +SOURCES = strmxor.cc + +INCLUDEPATH += ../bd ../../../tl ../../../db ../../../gsi +DEPENDPATH += ../bd ../../../tl ../../../db ../../../gsi +LIBS += -L$$DESTDIR -lklayout_bd -lklayout_tl -lklayout_db -lklayout_gsi diff --git a/src/buddies/strmxor/strmxor.pro b/src/buddies/strmxor/strmxor.pro deleted file mode 100644 index 78b09623d..000000000 --- a/src/buddies/strmxor/strmxor.pro +++ /dev/null @@ -1,13 +0,0 @@ - -include($$PWD/../../klayout.pri) - -TEMPLATE = app - -TARGET = strmxor -DESTDIR = $$OUT_PWD/../.. - -SOURCES = strmxor.cc - -INCLUDEPATH += ../bd ../../tl ../../db ../../gsi -DEPENDPATH += ../bd ../../tl ../../db ../../gsi -LIBS += -L$$DESTDIR -lklayout_bd -lklayout_tl -lklayout_db -lklayout_gsi diff --git a/src/buddies/unit_tests/bdBasicTests.cc b/src/buddies/unit_tests/bdBasicTests.cc new file mode 100644 index 000000000..d2649237a --- /dev/null +++ b/src/buddies/unit_tests/bdBasicTests.cc @@ -0,0 +1,204 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2017 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 "bdWriterOptions.h" +#include "bdReaderOptions.h" +#include "tlCommandLineParser.h" +#include "dbLayout.h" +#include "dbCell.h" + +#include "utHead.h" + +// Testing writer options +TEST(1) +{ + bd::GenericWriterOptions opt; + tl::CommandLineOptions cmd; + + opt.add_options (cmd); + + char *argv[] = { "x", + "-os=1.25", + "-od=0.125", + "--drop-empty-cells", + "--keep-instances", + "--no-context-info", + // CIF + "--blank-separator", + "--dummy-calls", + // DXF + "-op=2", + // GDS2 + "-ol=MYLIBNAME", + "-ov=250", + "--multi-xy-records", + "--no-timestamps", + "--no-zero-length-paths", + "--user-units=2.5", + "--write-cell-properties", + "--write-file-properties", + // OASIS + "-ob", + "-ok=9", + "-ot", + "--recompress", + "--subst-char=XY", + "--write-std-properties=2" + }; + + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + + db::Layout layout; + + db::SaveLayoutOptions stream_opt; + EXPECT_EQ (stream_opt.dont_write_empty_cells (), false); + EXPECT_EQ (stream_opt.keep_instances (), false); + EXPECT_EQ (stream_opt.write_context_info (), true); + EXPECT_EQ (stream_opt.get_options ().blank_separator, false); + EXPECT_EQ (stream_opt.get_options ().dummy_calls, false); + EXPECT_EQ (stream_opt.get_options ().polygon_mode, 0); + EXPECT_EQ (stream_opt.get_options ().libname, "LIB"); + EXPECT_EQ (stream_opt.get_options ().max_vertex_count, (unsigned int) 8000); + EXPECT_EQ (stream_opt.get_options ().multi_xy_records, false); + EXPECT_EQ (stream_opt.get_options ().write_timestamps, true); + EXPECT_EQ (stream_opt.get_options ().no_zero_length_paths, false); + EXPECT_EQ (tl::to_string (stream_opt.get_options ().user_units), "1"); + EXPECT_EQ (stream_opt.get_options ().write_cell_properties, false); + EXPECT_EQ (stream_opt.get_options ().write_file_properties, false); + EXPECT_EQ (stream_opt.get_options ().write_cblocks, false); + EXPECT_EQ (stream_opt.get_options ().compression_level, 2); + EXPECT_EQ (stream_opt.get_options ().strict_mode, false); + EXPECT_EQ (stream_opt.get_options ().recompress, false); + EXPECT_EQ (stream_opt.get_options ().subst_char, "*"); + EXPECT_EQ (stream_opt.get_options ().write_std_properties, 1); + + opt.configure (stream_opt, layout); + + EXPECT_EQ (stream_opt.scale_factor (), 1.25); + EXPECT_EQ (stream_opt.dbu (), 0.125); + EXPECT_EQ (stream_opt.dont_write_empty_cells (), true); + EXPECT_EQ (stream_opt.keep_instances (), true); + EXPECT_EQ (stream_opt.write_context_info (), false); + EXPECT_EQ (stream_opt.get_options ().blank_separator, true); + EXPECT_EQ (stream_opt.get_options ().dummy_calls, true); + EXPECT_EQ (stream_opt.get_options ().polygon_mode, 2); + EXPECT_EQ (stream_opt.get_options ().libname, "MYLIBNAME"); + EXPECT_EQ (stream_opt.get_options ().max_vertex_count, (unsigned int) 250); + EXPECT_EQ (stream_opt.get_options ().multi_xy_records, true); + EXPECT_EQ (stream_opt.get_options ().write_timestamps, false); + EXPECT_EQ (stream_opt.get_options ().no_zero_length_paths, true); + EXPECT_EQ (tl::to_string (stream_opt.get_options ().user_units), "2.5"); + EXPECT_EQ (stream_opt.get_options ().write_cell_properties, true); + EXPECT_EQ (stream_opt.get_options ().write_file_properties, true); + EXPECT_EQ (stream_opt.get_options ().write_cblocks, true); + EXPECT_EQ (stream_opt.get_options ().compression_level, 9); + EXPECT_EQ (stream_opt.get_options ().strict_mode, true); + EXPECT_EQ (stream_opt.get_options ().recompress, true); + EXPECT_EQ (stream_opt.get_options ().subst_char, "X"); + EXPECT_EQ (stream_opt.get_options ().write_std_properties, 2); +} + +static std::string cells2string (const db::Layout &layout, const std::set &cells) +{ + std::string res; + for (std::set::const_iterator c = cells.begin (); c != cells.end (); ++c) { + if (c != cells.begin ()) { + res += ","; + } + res += layout.cell_name (*c); + } + return res; +} + +// Testing writer options: cell resolution +TEST(2) +{ + // Build a layout with the hierarchy + // TOP -> A, B + // A -> B + // B -> C + // C -> D + db::Layout layout; + db::cell_index_type itop = layout.add_cell ("TOP"); + db::cell_index_type ia = layout.add_cell ("A"); + db::cell_index_type ib = layout.add_cell ("B"); + db::cell_index_type ic = layout.add_cell ("C"); + db::cell_index_type id = layout.add_cell ("D"); + layout.cell (itop).insert (db::CellInstArray (ia, db::Trans ())); + layout.cell (itop).insert (db::CellInstArray (ib, db::Trans ())); + layout.cell (ia).insert (db::CellInstArray (ib, db::Trans ())); + layout.cell (ib).insert (db::CellInstArray (ic, db::Trans ())); + layout.cell (ic).insert (db::CellInstArray (id, db::Trans ())); + + bd::GenericWriterOptions opt; + tl::CommandLineOptions cmd; + opt.add_options (cmd); + + std::set cells; + std::vector > valid_layers; + db::SaveLayoutOptions stream_opt; + + { + char *argv[] = { "x", + "--write-cells=A,-C,(C)", + }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + + opt.configure (stream_opt, layout); + + cells.clear (); + valid_layers.clear (); + stream_opt.get_cells (layout, cells, valid_layers); + + EXPECT_EQ (cells2string (layout, cells), "A,B,C"); + + { + char *argv[] = { "x", + "--write-cells=(C),(TOP)", + }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + + opt.configure (stream_opt, layout); + + cells.clear (); + valid_layers.clear (); + stream_opt.get_cells (layout, cells, valid_layers); + + EXPECT_EQ (cells2string (layout, cells), "TOP,C"); + + { + char *argv[] = { "x", + "--write-cells=(TOP),+B", + }; + cmd.parse (sizeof (argv) / sizeof (argv[0]), argv); + } + + opt.configure (stream_opt, layout); + + cells.clear (); + valid_layers.clear (); + stream_opt.get_cells (layout, cells, valid_layers); + + EXPECT_EQ (cells2string (layout, cells), "TOP,B,C,D"); +} diff --git a/src/buddies/unit_tests/unit_tests.pro b/src/buddies/unit_tests/unit_tests.pro new file mode 100644 index 000000000..0df5ec9dc --- /dev/null +++ b/src/buddies/unit_tests/unit_tests.pro @@ -0,0 +1,13 @@ + +TARGET = bd_tests + +include($$PWD/../../klayout.pri) +include($$PWD/../../lib_ut.pri) + +SOURCES = \ + bdBasicTests.cc \ + +INCLUDEPATH += ../src/bd +DEPENDPATH += ../src/bd + +LIBS += -L$$DESTDIR -lklayout_bd diff --git a/src/db/dbSaveLayoutOptions.h b/src/db/dbSaveLayoutOptions.h index 7b50d0a4d..be4688438 100644 --- a/src/db/dbSaveLayoutOptions.h +++ b/src/db/dbSaveLayoutOptions.h @@ -265,7 +265,7 @@ public: template void set_options (const T &options) { - m_options.insert (std::make_pair (options.format_name (), options.clone ())); + set_options (options.clone ()); } /** @@ -280,7 +280,13 @@ public: template void set_options (T *options) { - m_options.insert (std::make_pair (options->format_name (), options)); + std::map::iterator o = m_options.find (options->format_name ()); + if (o != m_options.end ()) { + delete o->second; + o->second = options; + } else { + m_options.insert (std::make_pair (options->format_name (), options)); + } } /** diff --git a/src/lib_ut.pri b/src/lib_ut.pri new file mode 100644 index 000000000..635dcefd1 --- /dev/null +++ b/src/lib_ut.pri @@ -0,0 +1,19 @@ + +DESTDIR_UT = $$OUT_PWD/../.. +DESTDIR = $$OUT_PWD/.. + +TEMPLATE = lib + +INCLUDEPATH += ../src ../../db ../../tl ../../gsi ../../laybasic ../../lay ../../ut +DEPENDPATH += ../src ../../db ../../tl ../../gsi ../../laybasic ../../lay ../../ut +LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut + +QMAKE_RPATHDIR += $$DESTDIR + +# Only on Windows, DESTDIR_TARGET is usable. On this platform, a blank happens to appear between +# $(DESTDIR) and $(TARGET) +win32 { + QMAKE_POST_LINK += $(COPY) $(DESTDIR_TARGET) $$DESTDIR_UT/$${TARGET}.ut +} else { + QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_UT/$${TARGET}.ut +} diff --git a/src/plugins/plugin_ut.pri b/src/plugins/plugin_ut.pri index fe3f42547..174698f52 100644 --- a/src/plugins/plugin_ut.pri +++ b/src/plugins/plugin_ut.pri @@ -1,17 +1,19 @@ -DESTDIR_KLP = $$OUT_PWD/../../.. +DESTDIR_UT = $$OUT_PWD/../../.. DESTDIR = $$OUT_PWD/.. TEMPLATE = lib -INCLUDEPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../common ../../../ut -DEPENDPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../common ../../../ut -LIBS += -L$$DESTDIR_KLP -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut +INCLUDEPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../ut +DEPENDPATH += ../src ../../../db ../../../tl ../../../gsi ../../../laybasic ../../../lay ../../../ut +LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay -lklayout_ut + +QMAKE_RPATHDIR += $$DESTDIR # Only on Windows, DESTDIR_TARGET is usable. On this platform, a blank happens to appear between # $(DESTDIR) and $(TARGET) win32 { - QMAKE_POST_LINK += $(COPY) $(DESTDIR_TARGET) $$DESTDIR_KLP/$${TARGET}.klp_ut + QMAKE_POST_LINK += $(COPY) $(DESTDIR_TARGET) $$DESTDIR_UT/$${TARGET}.ut } else { - QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_KLP/$${TARGET}.klp_ut + QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_UT/$${TARGET}.ut } diff --git a/src/tl/tlCommandLineParser.cc b/src/tl/tlCommandLineParser.cc index 27eadf24d..1bd7dcede 100644 --- a/src/tl/tlCommandLineParser.cc +++ b/src/tl/tlCommandLineParser.cc @@ -98,6 +98,22 @@ ArgBase::is_option () const return !m_option.short_option.empty () || !m_option.long_option.empty (); } +std::string +ArgBase::option_desc () const +{ + std::string res; + if (! m_option.short_option.empty ()) { + res += "-" + m_option.short_option; + } + if (! m_option.long_option.empty ()) { + if (! res.empty ()) { + res += "|"; + } + res += "--" + m_option.long_option; + } + return res; +} + // ------------------------------------------------------------------------ // Internal argument classes to implement info arguments @@ -531,43 +547,61 @@ CommandLineOptions::parse (int argc, char *argv[]) } - if (! arg->is_option ()) { + try { - arg->take_value (ex); + if (! arg->is_option ()) { - } else if (arg->wants_value ()) { - - if (ex.test ("=")) { arg->take_value (ex); + + } else if (arg->wants_value ()) { + + if (ex.test ("=")) { + arg->take_value (ex); + } else { + + ex.expect_end (); + ++i; + if (i == argc) { + throw tl::Exception (tl::to_string (QObject::tr ("Value missing"))); + } + + std::string arg_as_utf8 = tl::to_string (QString::fromLocal8Bit (argv [i])); + tl::Extractor ex_value (arg_as_utf8); + arg->take_value (ex_value); + + } + } else { - if (! ex.at_end ()) { - throw tl::Exception (tl::to_string (QObject::tr ("Syntax error in argument at \"..%1\" (use -h for help)").arg (tl::to_qstring (ex.get ())))); + if (ex.test ("=")) { + arg->take_value (ex); + } else { + arg->mark_present (arg->option ().inverted); } - ++i; - if (i == argc) { - throw tl::Exception (tl::to_string (QObject::tr ("Value missing for last argument (use -h for help)"))); - } - - std::string arg_as_utf8 = tl::to_string (QString::fromLocal8Bit (argv [i])); - tl::Extractor ex_value (arg_as_utf8); - arg->take_value (ex_value); } - } else { + // Execute the action if there is one + arg->action (this); - if (ex.test ("=")) { - arg->take_value (ex); + } catch (tl::Exception &ex) { + + std::string msg = "Parser error "; + if (i == argc) { + msg += "at end of argument list"; } else { - arg->mark_present (arg->option ().inverted); + msg += "at argument #" + tl::to_string (i); } + if (! arg->is_option ()) { + msg += " (option " + arg->option_desc () + ")"; + } + msg += ":"; + msg += ex.msg (); + + throw tl::Exception (msg); } - // Execute the action if there is one - arg->action (this); - } if (next_plain_arg != plain_args.end () && !(*next_plain_arg)->option ().optional) { diff --git a/src/tl/tlCommandLineParser.h b/src/tl/tlCommandLineParser.h index bd9583f8a..8cf3854eb 100644 --- a/src/tl/tlCommandLineParser.h +++ b/src/tl/tlCommandLineParser.h @@ -122,6 +122,12 @@ public: */ bool is_option () const; + /** + * @brief Returns an option description string + * This string is typically "-x|--xlong". + */ + std::string option_desc () const; + /** * @brief Gets a value from the extractor into the target of the argument */ @@ -173,21 +179,30 @@ private: /** * @brief A helper for extracting values by type + * + * @param repeated_hint Is true, if the value is supposed to be repeated + * @param enumerated Is true, if the value parser shall stop at a comma to allow for more entries in the next iteration */ template -inline void extract (tl::Extractor &ex, T &t, bool /*for_list*/ = false) +inline void extract (tl::Extractor &ex, T &t, bool /*repeated_hint*/, bool enumerated = false) { ex.read (t); + if (! enumerated) { + ex.expect_end (); + } } /** * @brief A specialization for the string type */ -inline void extract (tl::Extractor &ex, std::string &t, bool for_list = false) +inline void extract (tl::Extractor &ex, std::string &t, bool /*repeated_hint*/, bool enumerated = false) { if (*ex == '"' || *ex == '\'') { ex.read_quoted (t); - } else if (for_list) { + if (! enumerated) { + ex.expect_end (); + } + } else if (enumerated) { ex.read (t, ","); } else { t = ex.get (); @@ -203,13 +218,13 @@ inline void extract (tl::Extractor &ex, std::string &t, bool for_list = false) * @brief A specialization for a list of any type (vector) */ template -inline void extract (tl::Extractor &ex, std::vector &t, bool for_list = false) +inline void extract (tl::Extractor &ex, std::vector &t, bool repeated_hint, bool /*enumerated*/ = false) { while (! ex.at_end ()) { t.push_back (T ()); - extract (ex, t.back (), for_list); - if (for_list) { - ex.test (","); + extract (ex, t.back (), false, ! repeated_hint); + if (! repeated_hint && ! ex.test (",")) { + ex.expect_end (); } } } @@ -287,7 +302,7 @@ public: virtual void take_value (tl::Extractor &ex) { - extract (ex, *mp_value, !option ().repeated); + extract (ex, *mp_value, option ().repeated); } virtual void mark_present (bool inverted) @@ -327,7 +342,7 @@ public: { typedef typename type_without_const_ref::inner_type inner_type; inner_type t = inner_type (); - extract (ex, t, !option ().repeated); + extract (ex, t, option ().repeated); (mp_object->*mp_setter) (t); } diff --git a/src/ut/utMain.cc b/src/ut/utMain.cc index 99abb31e5..d1379cb97 100644 --- a/src/ut/utMain.cc +++ b/src/ut/utMain.cc @@ -803,7 +803,7 @@ main_cont (int argc, char **argv) // Search and initialize plugin unit tests QStringList name_filters; - name_filters << QString::fromUtf8 ("*.klp_ut"); + name_filters << QString::fromUtf8 ("*.ut"); QDir inst_dir (tl::to_qstring (tl::get_inst_path ())); QStringList inst_modules = inst_dir.entryList (name_filters); @@ -811,13 +811,13 @@ main_cont (int argc, char **argv) for (QStringList::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) { - QFileInfo klp_file (inst_dir.path (), *im); - if (klp_file.exists () && klp_file.isReadable ()) { + QFileInfo ut_file (inst_dir.path (), *im); + if (ut_file.exists () && ut_file.isReadable ()) { - std::string pp = tl::to_string (klp_file.absoluteFilePath ()); + std::string pp = tl::to_string (ut_file.absoluteFilePath ()); tl::log << "Loading plugin unit tests " << pp; - // NOTE: since we are using a different suffix ("*.klp_ut"), we can't use QLibrary. + // NOTE: since we are using a different suffix ("*.ut"), we can't use QLibrary. #ifdef _WIN32 // there is no "dlopen" on mingw, so we need to emulate it. HINSTANCE handle = LoadLibraryW ((const wchar_t *) tl::to_qstring (pp).constData ()); @@ -995,7 +995,7 @@ main_cont (int argc, char **argv) bool exclude = false; for (std::vector::const_iterator m = exclude_test_list.begin (); m != exclude_test_list.end (); ++m) { QRegExp re (tl::to_qstring (*m), Qt::CaseInsensitive, QRegExp::Wildcard); - if (re.indexIn (tl::to_qstring ((*i)->name ())) >= 0) { + if (re.indexIn (tl::to_qstring ((*i)->name ())) == 0) { exclude = true; break; } @@ -1003,7 +1003,7 @@ main_cont (int argc, char **argv) for (std::vector::const_iterator m = test_list.begin (); !exclude && m != test_list.end (); ++m) { QRegExp re (tl::to_qstring (*m), Qt::CaseInsensitive, QRegExp::Wildcard); - if (re.indexIn (tl::to_qstring ((*i)->name ())) >= 0) { + if (re.indexIn (tl::to_qstring ((*i)->name ())) == 0) { tl::info << " " << (*i)->name (); subset.push_back (*i); break;