From 2a6c2ee735f0009dd31529b109a6aa565bdb5400 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 19 Aug 2017 23:28:03 +0200 Subject: [PATCH] Tests and bug fixes for strmcmp and strmclip * ut framework now has a text file compare * Added tests for strm2txt, strmclip and strmcmp * Fixed the output of the PrintingDiffReceiver in some cases * Cell renaming does not give a difference in smart cell mapping mode --- src/buddies/src/bd/strmclip.cc | 2 +- src/buddies/src/bd/strmcmp.cc | 34 +- src/buddies/unit_tests/bdStrm2txtTests.cc | 43 ++ src/buddies/unit_tests/bdStrmclipTests.cc | 103 +++++ src/buddies/unit_tests/bdStrmcmpTests.cc | 535 ++++++++++++++++++++++ src/buddies/unit_tests/unit_tests.pro | 3 + src/db/dbLayoutDiff.cc | 65 +-- src/ut/utHead.h | 5 + src/ut/utMain.cc | 29 +- testdata/bd/strm2clip_au1.gds | Bin 0 -> 1986 bytes testdata/bd/strm2clip_au2.gds | Bin 0 -> 633 bytes testdata/bd/strm2clip_in.gds | Bin 0 -> 2954 bytes testdata/bd/strm2txt_au.txt | 58 +++ testdata/bd/strmcmp_in.gds | Bin 0 -> 2762 bytes testdata/bd/strmcmp_ref1.gds | Bin 0 -> 2762 bytes testdata/bd/strmcmp_ref2.gds | Bin 0 -> 2780 bytes testdata/bd/strmcmp_ref3.gds | Bin 0 -> 2762 bytes testdata/bd/strmcmp_ref4.gds | Bin 0 -> 2772 bytes testdata/bd/strmcmp_ref5.gds | Bin 0 -> 2534 bytes testdata/bd/strmcmp_ref6.gds | Bin 0 -> 2778 bytes testdata/bd/strmcmp_ref7.oas | Bin 0 -> 743 bytes testdata/bd/strmcmp_ref8.gds | Bin 0 -> 2762 bytes 22 files changed, 828 insertions(+), 49 deletions(-) create mode 100644 src/buddies/unit_tests/bdStrm2txtTests.cc create mode 100644 src/buddies/unit_tests/bdStrmclipTests.cc create mode 100644 src/buddies/unit_tests/bdStrmcmpTests.cc create mode 100644 testdata/bd/strm2clip_au1.gds create mode 100644 testdata/bd/strm2clip_au2.gds create mode 100644 testdata/bd/strm2clip_in.gds create mode 100644 testdata/bd/strm2txt_au.txt create mode 100644 testdata/bd/strmcmp_in.gds create mode 100644 testdata/bd/strmcmp_ref1.gds create mode 100644 testdata/bd/strmcmp_ref2.gds create mode 100644 testdata/bd/strmcmp_ref3.gds create mode 100644 testdata/bd/strmcmp_ref4.gds create mode 100644 testdata/bd/strmcmp_ref5.gds create mode 100644 testdata/bd/strmcmp_ref6.gds create mode 100644 testdata/bd/strmcmp_ref7.oas create mode 100644 testdata/bd/strmcmp_ref8.gds diff --git a/src/buddies/src/bd/strmclip.cc b/src/buddies/src/bd/strmclip.cc index e329b5242..74e43b583 100644 --- a/src/buddies/src/bd/strmclip.cc +++ b/src/buddies/src/bd/strmclip.cc @@ -193,7 +193,7 @@ BD_PUBLIC int strmclip (int argc, char *argv[]) "If given, this name will be used as the top cell name in the output file. " "By default the output's top cell will be \"CLIPPED_\" plus the input's top cell name." ) - << tl::arg ("*-r|--rect=\"l,b,r,t\"", &data, &ClipData::add_box, "Specifies a clip box", + << tl::arg ("*-r|--rect=\"l,b,r,t\"", &data, &ClipData::add_box, "Specifies a clip box", "This option specifies the box to clip in micrometer units. The box is given " "by left, bottom, right and top coordinates. This option can be used multiple times " "to produce a clip covering more than one rectangle." diff --git a/src/buddies/src/bd/strmcmp.cc b/src/buddies/src/bd/strmcmp.cc index 8f7c828ad..2bf4ca800 100644 --- a/src/buddies/src/bd/strmcmp.cc +++ b/src/buddies/src/bd/strmcmp.cc @@ -34,9 +34,9 @@ BD_PUBLIC int strmcmp (int argc, char *argv[]) generic_reader_options_a.set_group_prefix ("Input A"); bd::GenericReaderOptions generic_reader_options_b; - generic_reader_options_a.set_prefix ("b"); - generic_reader_options_a.set_long_prefix ("b-"); - generic_reader_options_a.set_group_prefix ("Input B"); + generic_reader_options_b.set_prefix ("b"); + generic_reader_options_b.set_long_prefix ("b-"); + generic_reader_options_b.set_group_prefix ("Input B"); std::string infile_a, infile_b; std::string top_a, top_b; @@ -133,7 +133,7 @@ BD_PUBLIC int strmcmp (int argc, char *argv[]) cmd.parse (argc, argv); if (top_a.empty () != top_b.empty ()) { - throw tl::Exception ("Both --top-a and --top-b top cells must be given"); + throw tl::Exception ("Both -ta|--top-a and -tb|--top-b top cells must be given"); } db::Layout layout_a; @@ -152,7 +152,7 @@ BD_PUBLIC int strmcmp (int argc, char *argv[]) db::LoadLayoutOptions load_options; generic_reader_options_b.configure (load_options); - tl::InputStream stream (infile_a); + tl::InputStream stream (infile_b); db::Reader reader (stream); reader.read (layout_b, load_options); } @@ -195,6 +195,30 @@ BD_PUBLIC int strmcmp (int argc, char *argv[]) db::Coord tolerance_dbu = db::coord_traits::rounded (tolerance / std::min (layout_a.dbu (), layout_b.dbu ())); bool result = false; + if (smart_cell_mapping && top_a.empty ()) { + + db::Layout::top_down_const_iterator t; + + t = layout_a.begin_top_down (); + if (t != layout_a.end_top_cells ()) { + top_a = layout_a.cell_name (*t); + ++t; + if (t != layout_a.end_top_cells ()) { + throw tl::Exception ("Top cell of first layout is not unique which is required for -c|--cell-mapping"); + } + } + + t = layout_b.begin_top_down (); + if (t != layout_b.end_top_cells ()) { + top_b = layout_b.cell_name (*t); + ++t; + if (t != layout_b.end_top_cells ()) { + throw tl::Exception ("Top cell of second layout is not unique which is required for -c|--cell-mapping"); + } + } + + } + if (! top_a.empty ()) { std::pair index_a = layout_a.cell_by_name (top_a.c_str ()); diff --git a/src/buddies/unit_tests/bdStrm2txtTests.cc b/src/buddies/unit_tests/bdStrm2txtTests.cc new file mode 100644 index 000000000..bfa924242 --- /dev/null +++ b/src/buddies/unit_tests/bdStrm2txtTests.cc @@ -0,0 +1,43 @@ + +/* + + 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 "utHead.h" +#include "bdCommon.h" + +BD_PUBLIC int strm2txt (int argc, char *argv[]); + +TEST(1) +{ + std::string input = ut::testsrc (); + input += "/testdata/gds/t10.gds"; + + std::string au = ut::testsrc (); + au += "/testdata/bd/strm2txt_au.txt"; + + std::string output = this->tmp_file (); + + char *argv[] = { "x", const_cast (input.c_str ()), const_cast (output.c_str ()) }; + + EXPECT_EQ (strm2txt (sizeof (argv) / sizeof (argv[0]), argv), 0); + + this->compare_text_files (output, au); +} diff --git a/src/buddies/unit_tests/bdStrmclipTests.cc b/src/buddies/unit_tests/bdStrmclipTests.cc new file mode 100644 index 000000000..0838aa0d4 --- /dev/null +++ b/src/buddies/unit_tests/bdStrmclipTests.cc @@ -0,0 +1,103 @@ + +/* + + 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 "utHead.h" +#include "bdCommon.h" +#include "dbReader.h" + +BD_PUBLIC int strmclip (int argc, char *argv[]); + +TEST(1A) +{ + std::string input = ut::testsrc (); + input += "/testdata/bd/strm2clip_in.gds"; + + std::string au = ut::testsrc (); + au += "/testdata/bd/strm2clip_au1.gds"; + + std::string output = this->tmp_file (); + + char *argv[] = { "x", const_cast (input.c_str ()), const_cast (output.c_str ()), "-r=0,-2,9,5", "-r=13,-2,16,3", "-r=13,5,16,7" }; + + EXPECT_EQ (strmclip (sizeof (argv) / sizeof (argv[0]), argv), 0); + + db::Layout layout; + + { + tl::InputStream stream (output); + db::Reader reader (stream); + reader.read (layout); + } + + this->compare_layouts (layout, au, ut::NoNormalization); +} + +TEST(1B) +{ + std::string input = ut::testsrc (); + input += "/testdata/bd/strm2clip_in.gds"; + + std::string au = ut::testsrc (); + au += "/testdata/bd/strm2clip_au1.gds"; + + std::string output = this->tmp_file (); + + char *argv[] = { "x", const_cast (input.c_str ()), const_cast (output.c_str ()), "-l=100/0" }; + + EXPECT_EQ (strmclip (sizeof (argv) / sizeof (argv[0]), argv), 0); + + db::Layout layout; + + { + tl::InputStream stream (output); + db::Reader reader (stream); + reader.read (layout); + } + + this->compare_layouts (layout, au, ut::NoNormalization); +} + +TEST(2) +{ + std::string input = ut::testsrc (); + input += "/testdata/bd/strm2clip_in.gds"; + + std::string au = ut::testsrc (); + au += "/testdata/bd/strm2clip_au2.gds"; + + std::string output = this->tmp_file (); + + char *argv[] = { "x", const_cast (input.c_str ()), const_cast (output.c_str ()), "-r=0,-2,9,5", "-t", "INV2", "-x=CLIP_OUT" }; + + EXPECT_EQ (strmclip (sizeof (argv) / sizeof (argv[0]), argv), 0); + + db::Layout layout; + + { + tl::InputStream stream (output); + db::Reader reader (stream); + reader.read (layout); + } + + this->compare_layouts (layout, au, ut::NoNormalization); +} + diff --git a/src/buddies/unit_tests/bdStrmcmpTests.cc b/src/buddies/unit_tests/bdStrmcmpTests.cc new file mode 100644 index 000000000..389b6eaaf --- /dev/null +++ b/src/buddies/unit_tests/bdStrmcmpTests.cc @@ -0,0 +1,535 @@ + +/* + + 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 "utHead.h" +#include "bdCommon.h" +#include "dbReader.h" +#include "tlLog.h" + +#include + +BD_PUBLIC int strmcmp (int argc, char *argv[]); + +class CaptureChannel : public tl::Channel +{ +public: + CaptureChannel () + { + // .. nothing yet .. + } + + std::string captured_text () const + { + return m_text.str (); + } + + void clear () + { + m_text.str (std::string ()); + } + +protected: + virtual void puts (const char *s) + { + m_text << s; + } + + virtual void endl () + { + m_text << "\n"; + } + + virtual void end () { } + virtual void begin () { } + +private: + std::ostringstream m_text; +}; + + +TEST(1) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + tl::info << "Self test"; + EXPECT_EQ (cap.captured_text (), "Self test\n"); + cap.clear (); + EXPECT_EQ (cap.captured_text (), ""); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref1.gds"; + + char *argv[] = { "x", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 0); + + EXPECT_EQ (cap.captured_text (), ""); +} + +TEST(2A) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref2.gds"; + + char *argv[] = { "x", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Boxes differ for layer 8/0 in cell RINGO\n" + "Not in b but in a:\n" + " (-1720,1600;23160,2000)\n" + "Not in a but in b:\n" + " (-1520,1600;23160,2000)\n" + "Texts differ for layer 8/1 in cell RINGO\n" + "Not in b but in a:\n" + " ('FB',r0 0,1800)\n" + "Not in a but in b:\n" + " ('BF',r0 0,1800)\n" + "Layouts differ\n" + ); +} + +TEST(2B) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref2.gds"; + + char *argv[] = { "x", "-s", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), ""); +} + +TEST(2C) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref2.gds"; + + char *argv[] = { "x", "-am=8/0", "-as", "-bm=8/0", "-bs", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Boxes differ for layer 8/0 in cell RINGO\n" + "Not in b but in a:\n" + " (-1720,1600;23160,2000)\n" + "Not in a but in b:\n" + " (-1520,1600;23160,2000)\n" + "Layouts differ\n" + ); +} + +TEST(2D) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref2.gds"; + + char *argv[] = { "x", "-m=1", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "...\n" + "Report is shortened after 0 lines.\n" + "Layouts differ\n" + ); +} + +TEST(2E) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref2.gds"; + + char *argv[] = { "x", "-ta=INV2", "-tb=INV2", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 0); +} + +TEST(2F) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref2.gds"; + + char *argv[] = { "x", "-u", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Bounding boxes differ for cell RINGO, (-1720,-800;25160,3800) vs. (-1700,-800;25160,3800)\n" + "Per-layer bounding boxes differ for cell RINGO, layer (8/0), (-1720,-450;25160,3250) vs. (-1520,-450;25160,3250)\n" + "Boxes differ for layer 8/0 in cell RINGO\n" + "Texts differ for layer 8/1 in cell RINGO\n" + "Layouts differ\n" + ); +} + +TEST(3A) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref3.gds"; + + char *argv[] = { "x", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Boxes differ for layer 8/0 in cell RINGO\n" + "Not in b but in a:\n" + " (-1720,1600;23160,2000)\n" + "Not in a but in b:\n" + " (-1721,1600;23160,2000)\n" + "Layouts differ\n" + ); +} + +TEST(3B) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref3.gds"; + + char *argv[] = { "x", "-t=0.001", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 0); +} + +TEST(4A) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref4.gds"; + + char *argv[] = { "x", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Paths differ for layer 3/0 in cell TRANS\n" + "Not in b but in a:\n" + " (0,-800;0,800) w=250 bx=0 ex=0 r=false\n" + "Not in a but in b:\n" + "Boxes differ for layer 3/0 in cell TRANS\n" + "Not in b but in a:\n" + "Not in a but in b:\n" + " (-125,-800;125,800)\n" + "Layouts differ\n" + ); +} + +TEST(4B) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref4.gds"; + + char *argv[] = { "x", "-p", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 0); +} + +TEST(5A) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref5.gds"; + + char *argv[] = { "x", "-u", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Instances differ in cell RINGO\n" + "Layouts differ\n" + ); +} + +TEST(5B) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref5.gds"; + + char *argv[] = { "x", "--expand-arrays", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 0); +} + +TEST(6A) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref6.gds"; + + char *argv[] = { "x", "-r", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Boxes differ for layer 8/0 in cell RINGO\n" + "Not in b but in a:\n" + " (-1720,1600;23160,2000)\n" + "Not in a but in b:\n" + " (-1720,1600;23160,2000) {1 {VALUE}}\n" + "Layouts differ\n" + ); +} + +TEST(6B) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref6.gds"; + + char *argv[] = { "x", "-np", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 0); +} + +TEST(7A) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref7.oas"; + + char *argv[] = { "x", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Layer names differ between layout a and b for layer 3/0: vs. NAME\n" + "Layouts differ\n" + ); +} + +TEST(7B) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref7.oas"; + + char *argv[] = { "x", "-nl", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 0); +} + +TEST(8A) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref8.gds"; + + char *argv[] = { "x", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1); + + EXPECT_EQ (cap.captured_text (), + "Cell TRANS is not present in layout b, but in a\n" + "Cell SNART is not present in layout a, but in b\n" + "Instances differ in cell INV2\n" + "Not in b but in a:\n" + " TRANS r0 *1 -400,0\n" + " TRANS r0 *1 -400,2800\n" + " TRANS m0 *1 400,0\n" + " TRANS m0 *1 400,2800\n" + "Not in a but in b:\n" + " SNART r0 *1 -400,0\n" + " SNART r0 *1 -400,2800\n" + " SNART m0 *1 400,0\n" + " SNART m0 *1 400,2800\n" + "Layouts differ\n" + ); +} + +TEST(8B) +{ + CaptureChannel cap; + + tl::warn.add (&cap, false); + tl::info.add (&cap, false); + tl::error.add (&cap, false); + + std::string input_a = ut::testsrc (); + input_a += "/testdata/bd/strmcmp_in.gds"; + + std::string input_b = ut::testsrc (); + input_b += "/testdata/bd/strmcmp_ref8.gds"; + + char *argv[] = { "x", "-c", const_cast (input_a.c_str ()), const_cast (input_b.c_str ()) }; + + EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 0); + + EXPECT_EQ (cap.captured_text (), + "Cell TRANS in a is renamed to SNART in b\n" + ); +} diff --git a/src/buddies/unit_tests/unit_tests.pro b/src/buddies/unit_tests/unit_tests.pro index 723ce3feb..eec620229 100644 --- a/src/buddies/unit_tests/unit_tests.pro +++ b/src/buddies/unit_tests/unit_tests.pro @@ -7,6 +7,9 @@ include($$PWD/../../lib_ut.pri) SOURCES = \ bdBasicTests.cc \ bdConverterTests.cc \ + bdStrm2txtTests.cc \ + bdStrmclipTests.cc \ + bdStrmcmpTests.cc INCLUDEPATH += ../src/bd diff --git a/src/db/dbLayoutDiff.cc b/src/db/dbLayoutDiff.cc index 6c75eea44..9e8b4b069 100644 --- a/src/db/dbLayoutDiff.cc +++ b/src/db/dbLayoutDiff.cc @@ -747,10 +747,6 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout common_cells.push_back (cb->first); } else { r.cell_name_differs (std::string (a.cell_name (cm.second)), cm.second, cb->first, cb->second); - differs = true; - if (flags & layout_diff::f_silent) { - return false; - } common_cells.push_back (a.cell_name (cm.second)); // use layout A cell name as reference } @@ -1176,7 +1172,7 @@ PrintingDifferenceReceiver::enough (tl::Channel &ch) } if (m_count == m_max_count) { - enough (tl::warn) << "..." << tl::endl << "layout_diff: report is shortened after " << (m_max_count - 1) << " lines."; + tl::warn << "..." << tl::endl << "Report is shortened after " << (m_max_count - 1) << " lines."; } throw tl::CancelException (); } @@ -1228,18 +1224,19 @@ PrintingDifferenceReceiver::print_diffs (const db::PropertiesRepository &pr, con for (typename std::vector >::const_iterator s = anotb.begin (); s != anotb.end (); ++s) { enough (tl::info) << " " << s->first.to_string () << tl::noendl; if (s->second != 0) { - tl::info << " [" << s->second << "]"; if (m_print_properties) { const db::PropertiesRepository::properties_set &props = pr.properties (s->second); for (db::PropertiesRepository::properties_set::const_iterator p = props.begin (); p != props.end (); ++p) { const tl::Variant &name = pr.prop_name (p->first); if (name.is_long ()) { - tl::info << " {" << int (name.to_long ()) << " {" << p->second.to_string () << "}}"; + tl::info << " {" << int (name.to_long ()) << " {" << p->second.to_string () << "}}" << tl::noendl; } else { - tl::info << " {{" << name.to_string () << "} {" << p->second.to_string () << "}}"; + tl::info << " {{" << name.to_string () << "} {" << p->second.to_string () << "}}" << tl::noendl; } } - tl::info << "}"; + tl::info << ""; + } else { + tl::info << " [" << s->second << "]"; } } else { tl::info << ""; @@ -1251,7 +1248,7 @@ void PrintingDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b) { try { - enough (tl::error) << "layout_diff: database units differ " << dbu_a << " vs. " << dbu_b; + enough (tl::error) << "Database units differ " << dbu_a << " vs. " << dbu_b; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1261,7 +1258,7 @@ void PrintingDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la) { try { - enough (tl::error) << "layout_diff: layer " << la.to_string () << " is not present in layout b, but in a"; + enough (tl::error) << "Layer " << la.to_string () << " is not present in layout b, but in a"; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1271,7 +1268,7 @@ void PrintingDifferenceReceiver::layer_in_b_only (const db::LayerProperties &lb) { try { - enough (tl::error) << "layout_diff: layer " << lb.to_string () << " is not present in layout a, but in b"; + enough (tl::error) << "Layer " << lb.to_string () << " is not present in layout a, but in b"; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1281,7 +1278,7 @@ void PrintingDifferenceReceiver::layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb) { try { - enough (tl::error) << "layout_diff: layer names differ between layout a and b for layer " << la.layer << "/" << la.datatype << ": " + enough (tl::error) << "Layer names differ between layout a and b for layer " << la.layer << "/" << la.datatype << ": " << la.name << " vs. " << lb.name; } catch (tl::CancelException) { // ignore cancel exceptions @@ -1292,7 +1289,7 @@ void PrintingDifferenceReceiver::cell_in_a_only (const std::string &cellname, db::cell_index_type /*ci*/) { try { - enough (tl::error) << "layout_diff: cell " << cellname << " is not present in layout b, but in a"; + enough (tl::error) << "Cell " << cellname << " is not present in layout b, but in a"; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1302,7 +1299,7 @@ void PrintingDifferenceReceiver::cell_in_b_only (const std::string &cellname, db::cell_index_type /*ci*/) { try { - enough (tl::error) << "layout_diff: cell " << cellname << " is not present in layout a, but in b"; + enough (tl::error) << "Cell " << cellname << " is not present in layout a, but in b"; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1312,7 +1309,7 @@ void PrintingDifferenceReceiver::cell_name_differs (const std::string &cellname_a, db::cell_index_type /*cia*/, const std::string &cellname_b, db::cell_index_type /*cib*/) { try { - enough (tl::error) << "layout_diff: cell " << cellname_a << " in a is renamed to " << cellname_b << " in b"; + enough (tl::error) << "Cell " << cellname_a << " in a is renamed to " << cellname_b << " in b"; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1322,7 +1319,7 @@ void PrintingDifferenceReceiver::bbox_differs (const db::Box &ba, const db::Box &bb) { try { - enough (tl::error) << "layout_diff: bounding boxes differ for cell " << m_cellname << ", " << ba.to_string () << " vs. " << bb.to_string (); + enough (tl::error) << "Bounding boxes differ for cell " << m_cellname << ", " << ba.to_string () << " vs. " << bb.to_string (); } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1338,36 +1335,20 @@ void PrintingDifferenceReceiver::begin_inst_differences () { try { - enough (tl::error) << "layout_diff: instances differ in cell " << m_cellname; + enough (tl::error) << "Instances differ in cell " << m_cellname; } catch (tl::CancelException) { // ignore cancel exceptions } } void -PrintingDifferenceReceiver::instances_in_a (const std::vector &insts_a, const std::vector &cell_names, const db::PropertiesRepository & /*props*/) +PrintingDifferenceReceiver::instances_in_a (const std::vector & /*insts_a*/, const std::vector & /*cell_names*/, const db::PropertiesRepository & /*props*/) { - try { - enough (tl::info) << "list for a:"; - for (std::vector ::const_iterator s = insts_a.begin (); s != insts_a.end (); ++s) { - print_cell_inst (*s, cell_names); - } - } catch (tl::CancelException) { - // ignore cancel exceptions - } } void -PrintingDifferenceReceiver::instances_in_b (const std::vector &insts_b, const std::vector &cell_names, const db::PropertiesRepository & /*props*/) +PrintingDifferenceReceiver::instances_in_b (const std::vector & /*insts_b*/, const std::vector & /*cell_names*/, const db::PropertiesRepository & /*props*/) { - try { - enough (tl::info) << "list for b:"; - for (std::vector ::const_iterator s = insts_b.begin (); s != insts_b.end (); ++s) { - print_cell_inst (*s, cell_names); - } - } catch (tl::CancelException) { - // ignore cancel exceptions - } } void @@ -1411,7 +1392,7 @@ void PrintingDifferenceReceiver::per_layer_bbox_differs (const db::Box &ba, const db::Box &bb) { try { - enough (tl::error) << "layout_diff: per-layer bounding boxes differ for cell " << m_cellname << ", layer (" << m_layer.to_string () << "), " + enough (tl::error) << "Per-layer bounding boxes differ for cell " << m_cellname << ", layer (" << m_layer.to_string () << "), " << ba.to_string () << " vs. " << bb.to_string (); } catch (tl::CancelException) { // ignore cancel exceptions @@ -1422,7 +1403,7 @@ void PrintingDifferenceReceiver::begin_polygon_differences () { try { - enough (tl::error) << "layout_diff: polygons differ for layer " << m_layer.to_string () << " in cell " << m_cellname; + enough (tl::error) << "Polygons differ for layer " << m_layer.to_string () << " in cell " << m_cellname; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1450,7 +1431,7 @@ void PrintingDifferenceReceiver::begin_path_differences () { try { - enough (tl::error) << "layout_diff: paths differ for layer " << m_layer.to_string () << " in cell " << m_cellname; + enough (tl::error) << "Paths differ for layer " << m_layer.to_string () << " in cell " << m_cellname; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1478,7 +1459,7 @@ void PrintingDifferenceReceiver::begin_box_differences () { try { - enough (tl::error) << "layout_diff: boxes differ for layer " << m_layer.to_string () << " in cell " << m_cellname; + enough (tl::error) << "Boxes differ for layer " << m_layer.to_string () << " in cell " << m_cellname; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1506,7 +1487,7 @@ void PrintingDifferenceReceiver::begin_edge_differences () { try { - enough (tl::error) << "layout_diff: edges differ for layer " << m_layer.to_string () << " in cell " << m_cellname; + enough (tl::error) << "Edges differ for layer " << m_layer.to_string () << " in cell " << m_cellname; } catch (tl::CancelException) { // ignore cancel exceptions } @@ -1534,7 +1515,7 @@ void PrintingDifferenceReceiver::begin_text_differences () { try { - enough (tl::error) << "layout_diff: texts differ for layer " << m_layer.to_string () << " in cell " << m_cellname; + enough (tl::error) << "Texts differ for layer " << m_layer.to_string () << " in cell " << m_cellname; } catch (tl::CancelException) { // ignore cancel exceptions } diff --git a/src/ut/utHead.h b/src/ut/utHead.h index dcb507b0e..b68cecc47 100644 --- a/src/ut/utHead.h +++ b/src/ut/utHead.h @@ -196,6 +196,11 @@ struct UT_PUBLIC TestBase */ void compare_layouts (const db::Layout &layout, const std::string &au_file, const db::LayerMap &lmap, bool read_all_others, NormalizationMode norm = WriteGDS2, db::Coord tolerance = 0); + /** + * @brief Compares two text files + */ + void compare_text_files (const std::string &path_a, const std::string &path_b); + /** * @brief The test's name * @return The name of the test diff --git a/src/ut/utMain.cc b/src/ut/utMain.cc index d1379cb97..b5ea53945 100644 --- a/src/ut/utMain.cc +++ b/src/ut/utMain.cc @@ -776,10 +776,37 @@ void TestBase::compare_layouts (const db::Layout &layout, const std::string &au_ } if (! equal) { - raise (tl::sprintf ("Compare failed - see %s vs %s\n", tmp_file, au_file + (n > 1 ? " and variants" : ""))); + raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s%s", + tl::to_string (QFileInfo (tl::to_qstring (tmp_file)).absoluteFilePath ()), + tl::to_string (QFileInfo (tl::to_qstring (au_file)).absoluteFilePath ()), + (n > 1 ? "\nand variants" : ""))); } } +static std::string read_file (const std::string &path) +{ + QFile file (tl::to_qstring (path)); + if (! file.open (QIODevice::ReadOnly | QIODevice::Text)) { + tl::warn << tl::sprintf ("Unable to open file %s", path); + } + + QByteArray ba = file.readAll (); + return std::string (ba.constData (), 0, ba.size ()); +} + +void TestBase::compare_text_files (const std::string &path_a, const std::string &path_b) +{ + std::string text_a = read_file (path_a); + std::string text_b = read_file (path_b); + + if (text_a != text_b) { + raise (tl::sprintf ("Compare failed - see:\n file 1: %s\n file 2: %s", + tl::to_string (QFileInfo (tl::to_qstring (path_a)).absoluteFilePath ()), + tl::to_string (QFileInfo (tl::to_qstring (path_b)).absoluteFilePath ()))); + } +} + + static int main_cont (int argc, char **argv); int diff --git a/testdata/bd/strm2clip_au1.gds b/testdata/bd/strm2clip_au1.gds new file mode 100644 index 0000000000000000000000000000000000000000..45056634a2fa200ef60746f0577cf4e6e67843e3 GIT binary patch literal 1986 zcmd^9O=ufO7@gVK+1Xv~#9r;lMMjVuTq4u7#CDRl^yJ2}D{y3EDQSBWgd7q=4L%es zRDl8x)Ts|LBw*T$OlV1O4hYp03QEzTAy9Pa!2ui8(8Kmnu%JJ-OrYQFPh-1w5ACsg z(0sf4-n=*OeY-DbQMS#Dx7^x9eEGPM6n#QL-OOQY}Qv+0RUYAm15N?q_V%k*}4N)Ln?6N)l$l``Xe@g1?5V}I59&U#&8oQM1KFQ%Wr9w_c zlv6?H3x>X3Qlc1_;|M62#NIWJ!3pXDMnpkhu@+b-cAJUh9lALn2JxCvNr@+`XpZ@NsE$aGsOlpPJMJVxgd49K!HM}7mE&KD|V8~Rny8`d4VOd#Fl z0)wRYWh@OlI^)1D9+;R4CduxWH!_@V0gjKfDB|rrGn#q9V6m{J>C6WUE)3cLR{TlgW|(I zT|zuKSY&u*Akv|J*c8Z!as|hS_y@#0yZZR>a5(#T2E_Y^hA^{-1UdQzs~9q~f*H&# zo_=9Q%y4;DW}qToMv-bJhFKij*cY;GXBWB4a)uxmy8S87{q?FF>GOEWngJwZIEnay}@~aX9BZG#SxYlObjo0L@JqoF&+_K#`2X} zpinKx53Uw=hE{e45lzMm{1aqEZnA>h`Gr@cmc8~DBSSYUHxtmoNkYQa3~Y=* S^JI9L1rIPWHH>7yzyJUMu;I-B literal 0 HcmV?d00001 diff --git a/testdata/bd/strm2clip_in.gds b/testdata/bd/strm2clip_in.gds new file mode 100644 index 0000000000000000000000000000000000000000..d69737d825d3df30ee78dd5d1a6302507e1c5644 GIT binary patch literal 2954 zcma);&r20i6vxk-_q;Rjsby+`CDBhPFcUQ+B2lwa3=MsWiJ*%XZGs?)hzg+uOM;+Q z)k1=7;VuY-T1AAoY8ez^e?TC($w$8Fd*;k>X2cm2^z-=M`@QGhd(J&iGGtjpRGYHw zU*u2~?W9J^gg=vGnTy>WMAhk%*7ipyd%nC~KGivYeCFkFo@z_teK}+D{q4O2L>Y(3 zlv`wx*=7+@T}9e;*KWCP@i3Dp^_|FitW=#znH_;Y6ZRJ^j4$FBbZ5bz0aY(9Ci$_G zVfG_#3;P4APQ!72%sl|lqR^cMiyU95dVGBLaeQH_g?;$-srrWaCVc+2kBI*e_xBOL zyNG>AsX8;V|BxTCe|X~{`*8oAO4S2@R`Qqjbiv~oaGZy$!(?T%p^bZRWJUscj8y7o~@7g zQ_=WbC*t4sP5esLQAgo^R}%QK*8{k}JHpH$h<>3|9gOkg-d^MWUI=aU-okzC$EWJ% zMZ|9h@sZmHxStO~_dW7>51)OiUi^^cho^`A*!wy52UMMUlKt5^@#o%%U#WU_F4 zckhKh%tSYHDy1uWT@1VAAMJyYvD~HjvFe%lvAxUjV@KQK$C{!YHL{m8OYy$0hWN4m ziTJURufZ7FEdT$Y-P!AB8~Z`wv-AVz|MY{^F3fAgdjM_38b&`*s&3lk?)~_oenK>Q zg#AMHjm?Xnsrm+gjByCk9)P}zXzN@sPxfg%y)<@ec-HLqnpj+EXun%-yx@on}vy3ZE#>VDpBvIQ+F*MvwY7z9Ymmo+YqCzOak|3xj z>p_C-!M7j~^eH03ryheM_8$lqd~(U1zB6}@Gb7HJpugpu^WAgrJ?Ea46dA@1YEBqd zi89no2k0cV1wWH*sH=nhM2*Q*Pv5h1Ltj6X&*zp;Exaifs5up_%P3VC?HkS$nKqHC zHOL@UXAn_qebR9@?>SEO7?UXRlgM~36g!j5y}sTI>Z=C)Yxo77Mew&zu~*mP^w>#} z^~l@BdY@vaVw4`SEzqoKI*VYH^J|JdIzQ_;zhzDNMt0P=RdruO7E7VxeB**z%ViF|}>#P>V z_J^(1;PBWPGBZS(2I-Y7_eS-OyO3M^oxPc|&JpsegNbP(tbmiej96h?jI86GP;Mx2 z!o)4^SNBvz-_VScSlOe6#>Qz$n4XHdZ`@8R&Na>?N>8C~uZ3b~#^_7P)v0gUe5>mv z6nnBWq?dZ>_qL86QOLWF(($|bBNRI`N{<`e=lVg`A%Cq~Z_w z7)KKp9EWLf@1sYAVpoOG{_Wsb_9y%s4&j)voo~k6JGjd%8WO zPlWSxpJ;vE53Lu99eos>cPU?wy|&=~9%!0lAm)Wo>|lf*_x29=H?L`7_EsKaKOV)d z=0keR&yU(Z!TqdgI-gL-NBHbf?A4VxJv2kC$KEfo-ly1UC|;jl()!GMtrvDKz}S*;g}y{231vs?3Szd;F}DEi%@KB@^*D-?y9AyHe?z;03_*9#~Re|zmR2k|{Q zIyih~1d*6#c7vXZ?i9l=`A6np$d|bm?Q2|!_8lrm`%d&m`#QoCHMExtrD)y2>1f~R zbhK~$yYIu8<^LaKI=l01`#h+8(er@$Kl5N?0CBx|51@ryMa%=C*j2B-doO=ro)AqO zXT2utCYQCIDfVsp(0kf=g}6E72dx>r#}_`uuI57d1A3yH9jw>1X0ZP@)@zDAPCs#1 z>zS;ZyzP_qp5N^~?>*rBey2~A5pNTBdj6uI} literal 0 HcmV?d00001 diff --git a/testdata/bd/strmcmp_ref1.gds b/testdata/bd/strmcmp_ref1.gds new file mode 100644 index 0000000000000000000000000000000000000000..fa837f4e2a317771de909276f480b397e7cf8199 GIT binary patch literal 2762 zcma);(MuFj6vofa&fb|_S2L5skSHmrP>VDpBvIQ+F*MvwY7z9Ymmo+YqCzOak|3xj z>p_C-!M7j~^eH03ryheM_8$lqd~(U1zB6}@Gb7HJpugpu^WAgrJ?Ea46dA@1YEBqd zi89no2k0cV1wWH*sH=nhM2*Q*Pv5h1Ltj6X&*zp;Exaifs5up_%P3VC?HkS$nKqHC zHOL@UXAn_qebR9@?>SEO7?UXRlgM~36g!j5y}sTI>Z=C)Yxo77Mew&zu~*mP^w>#} z^~l@BdY@vaVw4`SEzqoKI*VYH^J|JdIzQ_;zhzDNMt0P=RdruO7E7VxeB**z%ViF|}>#P>V z_J^(1;PBWPGBZS(2I-Y7_eS-OyO3M^oxPc|&JpsegNbP(tbmiej96h?jI86GP;Mx2 z!o)4^SNBvz-_VScSlOe6#>Qz$n4XHdZ`@8R&Na>?N>8C~uZ3b~#^_7P)v0gUe5>mv z6nnBWq?dZ>_qL86QOLWF(($|bBNRI`N{<`e=lVg`A%Cq~Z_w z7)KKp9EWLf@1sYAVpoOG{_Wsb_9y%s4&j)voo~k6JGjd%8WO zPlWSxpJ;vE53Lu99eos>cPU?wy|&=~9%!0lAm)Wo>|lf*_x29=H?L`7_EsKaKOV)d z=0keR&yU(Z!TqdgI-gL-NBHbf?A4VxJv2kC$KEfo-ly1UC|;jl()!GMtrvDKz}S*;g}y{231vs?3Szd;F}DEi%@KB@^*D-?y9AyHe?z;03_*9#~Re|zmR2k|{Q zIyih~1d*6#c7vXZ?i9l=`A6np$d|bm?Q2|!_8lrm`%d&m`#QoCHMExtrD)y2>1f~R zbhK~$yYIu8<^LaKI=l01`#h+8(er@$Kl5N?0CBx|51@ryMa%=C*j2B-doO=ro)AqO zXT2utCYQCIDfVsp(0kf=g}6E72dx>r#}_`uuI57d1A3yH9jw>1X0ZP@)@zDAPCs#1 z>zS;ZyzP_qp5N^~?>*rBey2~A5pNTBdj6uI} literal 0 HcmV?d00001 diff --git a/testdata/bd/strmcmp_ref2.gds b/testdata/bd/strmcmp_ref2.gds new file mode 100644 index 0000000000000000000000000000000000000000..1903c32aaafadf60517b2b6101ebc6e521fdb31e GIT binary patch literal 2780 zcma);-%Aux6vxlb?%vs5*D@8skSHlAFpD%JBvIRbh@s(bQX=SMFF}w*M1@d-B|%V6 z)`JAugKt3~=uKGu^{Do$_$Iji?N!8og#BBE z?jB+vRH~gB%0Hk-?C-80WF7Xupj5lB&&v5Fz4+z;pJHZr62E0?tYebn{9b1gCHG5I zn_}xDW6Z$N=m|>Yh;sE>D|xPs%1w77_w4`f&231Gkk{-@OcP-StmIk53{_)v9&d%Z zLxB}0u5-P*t0MZ0Vw}Xx9&HphR!hq4RMdWBciOP7aVAlA3g`Ahsdi?JejTwoWtUU0 zPj-g%dR}thHc=x6aW`>vd~bd!)y|C4V@DfYKgc@7uT`o&Ue9%g{M>reyp?K? z%YSPeMObnirp>jF8d0j973r&yXlxMM)4@BuZO0_fN^f<3}(dXZZUa9tM zdq|%M$LBf`{jRT~SE?O#6zq3tUyoc{v43}ksZkL9LaBBzLXUlWjs2S!+UULI2gt{x z+Rc1OZ~O6awhysCD?;Zz&hb9}dsKU6B~A~`AnTF)IoA7BI}OI`vrD4Sy%D`q?b)Sx zeNDIM^Cv~GRC`Ug=<_@MuF0YVcNDpII3LrDt`!=Eo}r_5x`sf0TZ}{I7mchjG2Q2cV5uW9SD;wVPhqdoO;VpAbzP zX1$PglgpxKs=Z1dx=&lrF>Vg`5wvHJ$5WqbH*=x*0X@;R4%Q3p8RUPI^+L7B=_hW9 zp2@n&8$Ma@`Q6&{?gQ5ES2~}L+=u@2l4aE>JZUi`-;(afTaNn))--O&XtC(kc9qf{ dH?iT)&o`-fHf9{pjHfuyS15SnaN|-b`UBdIKjr`c literal 0 HcmV?d00001 diff --git a/testdata/bd/strmcmp_ref3.gds b/testdata/bd/strmcmp_ref3.gds new file mode 100644 index 0000000000000000000000000000000000000000..2a465c3f45a260eb34fb2529bbf0c2362ddea44a GIT binary patch literal 2762 zcma);-%Aux6vxlb&fb|_e`G3xVNp_0U>0gdNTRl7VraOV)FS9(FF}w*M1@d-B|%V6 z)`JAugKt3~=ug|7ecKFNt;<@a~sm0fYJhh~vbs44dWBnsJBGV>P zH3k`^Y7HW4t4li0_Fcy*A7c_Feh?YYgkoosx!>2DL4DbPe;vP|vjqO~DfaSuoE|$V zupW84S?^QqREW|ewiTLnO=k%#bAC;+N9Si9=hsYhvkt!=#a@wL1<${|hWt-(e{0Y^ zK<=YLu`@&a59pEmr|Snb6)Hy<4bs#ZAgcWd-7ZEE|#K=0{3FU?Y zCrsSresxbp^cBrGg_S*8Xl$I8gz4$1`^N3G;an3;qVzQC_DU#rW{iFVxw`Z%n{RZz zgkn#2h4fM{{oXdwBMNypQ96D%e}rOZM(J^*4Xz(#9rD)*#U8KcKEwXpev^F*#U8i+ ztqC+?-f@@~_da?=D0Y<(?cWZ*m(mk_1ODG*83DY4ae)#%UYj#r}aXyrvxjy*Rut)1-e|kU>5G literal 0 HcmV?d00001 diff --git a/testdata/bd/strmcmp_ref4.gds b/testdata/bd/strmcmp_ref4.gds new file mode 100644 index 0000000000000000000000000000000000000000..8aa4781b29dbd950ecf92248c4c6f9ff37b08caf GIT binary patch literal 2772 zcmai$&r4KM6vxlJnYr)HI9jO)hD1qGftjQkA&J^lilO05QiGt&HbIa?M2293B|%Ut zYav0la2EuEt|B5_wG4`|KOh)z<&g9Gp1JSz-ZkG-7(T=I-0wa2$GK-DMV57gnqrpy ziyW$>20Bh{!SCc)>gqrrQGGnw-TUO+;OBS6^VyZti?0fKYD$Lt(n{q=dWUjE35Q5k zTV#={v52T;f82Gq@40UI7?UXWoydAB6rD+l1HL~I^p`Ef*YN?}CGe+D(aY;meypUx ze&p?BzfaMr5a!3&W_Z>$-6gQh`87ok&(A*2uNmuPA3h#M-;rMh_rJY{{Eu;dYw$fp z?xRA{na279e&qg9iG%FJ`DcZq|L2bf^Sd*y`)31rXNcm5G2fI>bf(U4Q)Hz$N(~H+ zo}omVC|xU6li?~U-@(kN0Iq`Fqv_%=+~Sq;##yS*asjvCcl8 z=@wV6x63bB&;%kLZIn2lf-p51cJert7VK+`NtBwz4ZakL&W!MHAXi7_bSd##-<(kN zc!%LPZf<)Mx2BMH6C2|f^jj!8Gt7^3sH?<5_91_@Q1oa&R~*(?sXSS?Q1qzvZ;j!K z@~+FY`4yl>grcjwv3@65xurRHx?Q(4hrN6xO5PWW&W!TozFM_E^IrRfqNiF7f6UC! zb)x+>-?U#SI_fCc`I5dLYi-8)Jyg6JGV(ZLWu&g~7(Z$Z;W7cM=*dOV7*77V}b z=f~aR<(F4A-4D3ODSY=RdU-X<56>X`vGz;s_bECJM*CCC+Mj-_{X)@G%hCR-F73~p z)qbJqRbASj(cJ*=r@^8acNG2Za6hUMUCS7So*|?DbpxkS4PVcD9c+(2h+oW+fuSqI zy4N|ix+_+?7*@%D(g%%L`dWCbela|Ds2CnQ*%KaXH#@4amJ1u67jUOwptI!B#)U^+-flzeSW7JcipAe0oV815& zCRVhcDf$k-@t(F`VB9?NgZ3=e|IDZ8YTn2n@Dtr^XTPRBi}jykzozI>{_(ro&t%`k zZJ+G-;+5L--UIgUSNeDn;~nBk&t3FtbhmMQi~8MM?lazvF1(nO-clPtCt{1BBCNF!IB`T zC+i`C?7_Dn5cDY`!lxdCBJ2+c1fN`Tr|+3F$C+8&v4!2w@}2v==iYP9y+ej9>k74{ zEax}5)I=@RNnO$Z#0(8CfNr=za90LEj(Yx7xb3EUm;a5uP6Dj zl1cU>ZZG>os!o&D{21E-&$`fC0?QmtR4@DR4XAoWd=uUO&KlxBM*h~| zyNB3El&Ujh>yP*m`=|dLWFPXMSE?TRvr@lw5Z@f;D!K>K_$^U$1Cu=O?*@}7-7Zlb zO6(8UnBmch6J+Oza*f(6wcH!!oBl+8?e~6~+mslwr{+-VArWT4PM%kpp<;~A6YNkk z6xm_wI`^x;E26Jx#u>~U&_QEkx1`L@R?9cC(}jIaF^RIXsM|}W>dXZH24eL{mhIP4 zFQw|~o|s?jCFgAmJz@}d3#H?8^GB&Vvzi|nZStRk>_hxIrRvFk?lY{AkyQuUrb+C#bd3%feEeajny`=|OPe9ep zV$AP^@lo4H$j_?K`-nQ;$Nzw;msgYg@Qkn@Yd^>SkgC&2vOl{l{@gq9D^<@fC;Myq z#9w<#{7Thp`ov$md*8KKl;Rsj&K>GwT5)T|M&ZuTQMSz-RqS=qjbaRcZT z(D{bf6wZoLbu$plb>yrOO?R?i$iA5s@iSGg@W*;>`vt}=AU^2Kp;w=URNXAZ;z#^M zS5LBE=*(gL$Jj4aJ;^_POZ-gs&D;pd{@}Tv|Dac}|F8?DH!R literal 0 HcmV?d00001 diff --git a/testdata/bd/strmcmp_ref6.gds b/testdata/bd/strmcmp_ref6.gds new file mode 100644 index 0000000000000000000000000000000000000000..e45441f4ddba7c7c15a98e02c8ded8ed33e53f6b GIT binary patch literal 2778 zcmai$(MuFj6vofa&fb|_S2GpCkSHlAG>bGNBvIQ+Q7qhbsYTGoUV$jd_R3nE9+{L_ zkGNf|_bGNNMd`7&1)4QYXA!J$d`+=O$7dbK*GzP=4!<77zAL^8o_~84@t@-UR-t={ z*vEuoXNK|*=n?yu>jznf`_Bo*?(5UKen~IBI?7eF4eRPvzSZ>- ziapsG(o4Pcd)q{hD8$`F>G<9J6^fl1rN@odyMB;$h+i!fd%T|e4EeeJCV30R9+&^t zIGV8FI82LsA3Y)zyDEh8w}bDcJPS>aGqI5 z5suG&qV+XDv|cE7^igo$rF=bdZNdFL&@_u6=7mt~V1yp`_73+quW4cSmLDS@k78Hz zA-(0tM{S?repWP{PpIP~eD)~z%1WFbnjzLB_sgvJDRvr)*Qb}XKJ#AdgxE*k>el+~&b(_hD8Um&zdO`NHDPLnR$*qys-0qo51r&(Cz4n=d_?{dc z9JzW8D>2RNIz1KLDTXZhN9JJ2m$@G8YgmZ(9o~rco$QVFb%ZBsD3^=t(Yk>%(Z12? zXy5pE--j{F|3AodcIVmdc~JhM=K*v7c|bIA0_%D;EyS8!hTfyt!Qgue&6BMG*5f^a ztSe!j2*nP)YUK{fw5ej>@EF=YxL@dfZN0*NbJ!2GX7D~=_!PUEi_#O_>|nj7HG_Ok zv0hW`ar%k7TF+$NN0tw_p(Q$)f;eX&M4wrilzk4sqpc!6m)nq7b z1L^v;DabYWTfSSBNwan*kzpeW>PZ;IK_h4XLlIdV} z*5d6jYP5*Q?OG&B38RG@bg|MRoh-C)r z#(V9Vv7w2fvWMTbuZqbsnl#y@=&Ct8;ZMd+xd}aWqH;=Ij+lDTw`?rs@Jcn|z%7>^ z^i-&vtMCpvC@D|9RlYN}X=NljIeSrgGrp~g&KDzReJi)bU0OG`tFJw=a)w*ZOZ}Ke zbg`4O4^-q`{lHz*4&BGvh%PSUU_A51kniD^a%2}}ylIG`c82Hpl>d6Re6Q>*17Y9F zd}j&OP0MDbPiX1`G4WesSB0F7?ta!Y8hm4^C+6OM#KY={wd*~vn%Kk4>7nzGbSzMh V*!~aZbQA#RKHtB>(*IciKLJv${B8gM literal 0 HcmV?d00001 diff --git a/testdata/bd/strmcmp_ref8.gds b/testdata/bd/strmcmp_ref8.gds new file mode 100644 index 0000000000000000000000000000000000000000..251c916d3fda86c07d906b6fcd2a675cfd8ab740 GIT binary patch literal 2762 zcma);-%Aux6vxlb&fb|_S2GpCkSHlAPzyC9BvIQ+F*MvwY7z9Ymmo+YqCzOak|3xj z>p_C-!M7j~^eH03ryheM><-d1q68Ouf=;ie|KW0*7 zKk|07->2wQjPhe_3q0$Z&JtMW{F69EWLf?W0D7qN_q^{&w)bl;+^+b)3>1*7Aucbx$ZdGtQ6mYS;ek2kjS%o^B8M z6XE<^C)!{0UHgTiqmF|8F6H|%*B0#GeNA&5M86P<4o3K~Z*Q@G3z`;sZ|M={<56_A z5b|4oew^)N?9ZyE^AYFx5Z^tDUS5s!!!yi&%>5$!eTq)Q@&5F(_GjK{zfkn_a=gE) zNBgs9v|lKCRgd;(cl%wVK?&|C`rhGuR1>;ZXcT&ejN0u6c9R;t#&14;d+pN)@tzzT z8o4}*k?3Z2o$iWm7sD+1Px@dembn@oYgmkq9o~$No$QN_b%r}?XfEeBqJ4v>qhn(; z(Xokdehh7ve?LffcKcanKPY|H{ebyD{a||#`!%gu%)gEOnxe<~C+}!K zlYLXSe6rt*yS3-t2dv+(^vO+(w}~q~f5EHKy~gn=>U(o(K(8ih6b9mH