mirror of https://github.com/KLayout/klayout.git
Added more tests for strmcmp, first version of better strmxor
This commit is contained in:
parent
2a6c2ee735
commit
6e3bf68da9
|
|
@ -21,6 +21,7 @@ SOURCES = \
|
|||
strm2gdstxt.cc \
|
||||
strm2txt.cc \
|
||||
strmcmp.cc \
|
||||
strmxor.cc \
|
||||
|
||||
HEADERS = \
|
||||
bdCommon.h \
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ BD_PUBLIC int strmcmp (int argc, char *argv[])
|
|||
)
|
||||
<< tl::arg ("-s|--silent", &silent, "Enables silent mode",
|
||||
"In silent mode, no differences are printed, but the exit code indicates whether "
|
||||
"the layout are the same (0) or differences exist (> 0)."
|
||||
"the layouts are the same (0) or differences exist (> 0)."
|
||||
)
|
||||
<< tl::arg ("#!--with-text-orientation", &no_text_orientation, "Compares orientations for texts",
|
||||
"With this option, text orientation is compared too. The position of the "
|
||||
|
|
|
|||
|
|
@ -0,0 +1,290 @@
|
|||
|
||||
/*
|
||||
|
||||
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 "bdReaderOptions.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbTilingProcessor.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbWriter.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
#include "tlCommandLineParser.h"
|
||||
|
||||
BD_PUBLIC int strmxor (int argc, char *argv[])
|
||||
{
|
||||
bd::GenericReaderOptions generic_reader_options_a;
|
||||
generic_reader_options_a.set_prefix ("a");
|
||||
generic_reader_options_a.set_long_prefix ("a-");
|
||||
generic_reader_options_a.set_group_prefix ("Input A");
|
||||
|
||||
bd::GenericReaderOptions generic_reader_options_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, output;
|
||||
std::string top_a, top_b;
|
||||
bool dont_summarize_missing_layers = false;
|
||||
bool silent = false;
|
||||
std::vector<double> tolerances;
|
||||
int tolerance_bump = 10000;
|
||||
int threads = 1;
|
||||
double tile_size = 0.0;
|
||||
|
||||
tl::CommandLineOptions cmd;
|
||||
generic_reader_options_a.add_options (cmd);
|
||||
generic_reader_options_b.add_options (cmd);
|
||||
|
||||
cmd << tl::arg ("input_a", &infile_a, "The first input file (any format, may be gzip compressed)")
|
||||
<< tl::arg ("input_b", &infile_b, "The second input file (any format, may be gzip compressed)")
|
||||
<< tl::arg ("?output", &output, "The output file to which the XOR differences are written",
|
||||
"This argument is optional. If not given, the exit status along indicates whether the layouts "
|
||||
"are identical or not."
|
||||
)
|
||||
<< tl::arg ("-ta|--top-a=name", &top_a, "Specifies the cell to take as top cell from the first layout",
|
||||
"Use this option to take a specific cell as the top cell from the first layout. All "
|
||||
"cells not called directly or indirectly from this cell are ignored. If you use this option, "
|
||||
"--top-b must be specified too and can be different from the first layout's top cell."
|
||||
)
|
||||
<< tl::arg ("-tb|--top-b=name", &top_b, "Specifies the cell to take as top cell from the second layout",
|
||||
"See --top-a for details."
|
||||
)
|
||||
<< tl::arg ("-s|--silent", &silent, "Enables silent mode",
|
||||
"In silent mode, no summary is printed, but the exit code indicates whether "
|
||||
"the layouts are the same (0) or differences exist (> 0)."
|
||||
)
|
||||
<< tl::arg ("-l|--layer-details", &dont_summarize_missing_layers, "Output details about differences for missing layers",
|
||||
"With this option, missing layers are treated as \"empty\" and the whole layer of the other "
|
||||
"layout is output. Without this option, a message is printed for missing layers instead."
|
||||
)
|
||||
<< tl::arg ("-t|--tolerance=values", &tolerances, "Specifies tolerances for the geometry compare",
|
||||
"This option can take multiple tolerance values. The values are given in micrometer units and "
|
||||
"are separated by a comma. If a tolerance is given, XOR differences are "
|
||||
"only reported when they are larger than the tolerance value. Tolerance values must be given in "
|
||||
"ascending order."
|
||||
)
|
||||
<< tl::arg ("-n|--threads=threads", &threads, "Specifies the number of threads to use",
|
||||
"If given, multiple threads are used for the XOR computation. This way, multiple cores can "
|
||||
"be utilized."
|
||||
)
|
||||
<< tl::arg ("-p|--tiles=size", &tile_size, "Specifies tiling mode",
|
||||
"In tiling mode, the layout is divided into tiles of the given size. Each tile is computed "
|
||||
"individually. Multiple tiles can be processed in parallel on multiple cores."
|
||||
)
|
||||
<< tl::arg ("-b|--layer-bump=offset", &tolerance_bump, "Specifies the layer number offset to add for every tolerance",
|
||||
"This value is the number added to the original layer number to form a layer set for each tolerance "
|
||||
"value. If this value is set to 1000, the first tolerance value will produce XOR results on the "
|
||||
"original layers. A second tolerance value will produce XOR results on the original layers + 1000. "
|
||||
"A third tolerance value will produce XOR results on the original layers + 2000."
|
||||
)
|
||||
;
|
||||
|
||||
cmd.brief ("This program will compare two layout files with a geometrical XOR operation");
|
||||
|
||||
cmd.parse (argc, argv);
|
||||
|
||||
if (top_a.empty () != top_b.empty ()) {
|
||||
throw tl::Exception ("Both -ta|--top-a and -tb|--top-b top cells must be given");
|
||||
}
|
||||
|
||||
if (tolerances.empty ()) {
|
||||
tolerances.push_back (0.0);
|
||||
} else {
|
||||
for (std::vector<double>::const_iterator t = tolerances.begin () + 1; t != tolerances.end (); ++t) {
|
||||
if (*(t - 1) > *t - db::epsilon) {
|
||||
throw tl::Exception ("Tolerance values (-t|--tolerances) must be given in ascending order");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db::Layout layout_a;
|
||||
db::Layout layout_b;
|
||||
|
||||
{
|
||||
db::LoadLayoutOptions load_options;
|
||||
generic_reader_options_a.configure (load_options);
|
||||
|
||||
tl::InputStream stream (infile_a);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout_a, load_options);
|
||||
}
|
||||
|
||||
{
|
||||
db::LoadLayoutOptions load_options;
|
||||
generic_reader_options_b.configure (load_options);
|
||||
|
||||
tl::InputStream stream (infile_b);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout_b, load_options);
|
||||
}
|
||||
|
||||
if (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 and cannot be determined automatically");
|
||||
}
|
||||
}
|
||||
|
||||
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 and cannot be determined automatically");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::pair<bool, db::cell_index_type> index_a = layout_a.cell_by_name (top_a.c_str ());
|
||||
std::pair<bool, db::cell_index_type> index_b = layout_b.cell_by_name (top_b.c_str ());
|
||||
|
||||
if (! index_a.first) {
|
||||
throw tl::Exception ("'" + top_a + "' is not a valid cell name in first layout");
|
||||
}
|
||||
if (! index_b.first) {
|
||||
throw tl::Exception ("'" + top_b + "' is not a valid cell name in second layout");
|
||||
}
|
||||
|
||||
std::map<db::LayerProperties, std::pair<int, int> > l2l_map;
|
||||
|
||||
for (db::Layout::layer_iterator l = layout_a.begin_layers (); l != layout_a.end_layers (); ++l) {
|
||||
l2l_map.insert (std::make_pair (*(*l).second, std::make_pair (-1, -1))).first->second.first = (*l).first;
|
||||
}
|
||||
for (db::Layout::layer_iterator l = layout_b.begin_layers (); l != layout_b.end_layers (); ++l) {
|
||||
l2l_map.insert (std::make_pair (*(*l).second, std::make_pair (-1, -1))).first->second.second = (*l).first;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
db::TilingProcessor proc;
|
||||
proc.set_dbu (std::min (layout_a.dbu (), layout_b.dbu ()));
|
||||
proc.set_threads (std::max (1, threads));
|
||||
if (tile_size > db::epsilon) {
|
||||
proc.tile_size (tile_size, tile_size);
|
||||
}
|
||||
proc.tile_border (tolerances.back () * 2.0, tolerances.back () * 2.0);
|
||||
|
||||
db::Layout output_layout;
|
||||
output_layout.dbu (proc.dbu ());
|
||||
|
||||
db::cell_index_type output_top = output_layout.add_cell ("XOR");
|
||||
|
||||
std::vector<unsigned int> output_layers;
|
||||
|
||||
int index = 1;
|
||||
|
||||
for (std::map<db::LayerProperties, std::pair<int, int> >::const_iterator ll = l2l_map.begin (); ll != l2l_map.end (); ++ll) {
|
||||
|
||||
if (ll->second.first < 0 && ! dont_summarize_missing_layers) {
|
||||
|
||||
tl::warn << "Layer " << ll->first.to_string () << " is not present in first layout, but in second";
|
||||
result = false;
|
||||
|
||||
} else if (ll->second.second < 0 && ! dont_summarize_missing_layers) {
|
||||
|
||||
tl::warn << "Layer " << ll->first.to_string () << " is not present in second layout, but in first";
|
||||
result = false;
|
||||
|
||||
} else {
|
||||
|
||||
std::string in_a = "a" + tl::to_string (index);
|
||||
std::string in_b = "b" + tl::to_string (index);
|
||||
|
||||
if (ll->second.first < 0) {
|
||||
proc.input (in_a, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_a, db::RecursiveShapeIterator (layout_a, layout_a.cell (index_a.second), ll->second.first));
|
||||
}
|
||||
|
||||
if (ll->second.second < 0) {
|
||||
proc.input (in_b, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_b, db::RecursiveShapeIterator (layout_b, layout_b.cell (index_b.second), ll->second.second));
|
||||
}
|
||||
|
||||
std::string expr = "var x=" + in_a + "^" + in_b + "; ";
|
||||
|
||||
int tol_index = 1;
|
||||
for (std::vector<double>::const_iterator t = tolerances.begin (); t != tolerances.end (); ++t) {
|
||||
|
||||
std::string out = "o" + tl::to_string (index) + "_" + tl::to_string (tol_index);
|
||||
|
||||
db::LayerProperties lp = ll->first;
|
||||
if (lp.layer >= 0) {
|
||||
lp.layer += (tol_index - 1) * tolerance_bump;
|
||||
}
|
||||
|
||||
unsigned int output_layer = output_layout.insert_layer (lp);
|
||||
output_layers.push_back (output_layer);
|
||||
|
||||
// @@@ TODO: silent mode
|
||||
proc.output (out, output_layout, output_top, output_layer);
|
||||
|
||||
if (*t > db::epsilon) {
|
||||
expr += "x=x.sized(-int(" + tl::to_string (*t) + "/_dbu)/2).sized(int(" + tl::to_string (*t) + "/_dbu)/2); ";
|
||||
}
|
||||
expr += "_output(" + out + ",x); ";
|
||||
|
||||
}
|
||||
|
||||
proc.queue (expr);
|
||||
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
}
|
||||
|
||||
// Runs the processor
|
||||
|
||||
proc.execute ("Running XOR");
|
||||
|
||||
// Write the output layout
|
||||
|
||||
if (! output.empty()) {
|
||||
|
||||
db::SaveLayoutOptions save_options;
|
||||
save_options.set_format_from_filename (output);
|
||||
|
||||
tl::OutputStream stream (output);
|
||||
db::Writer writer (save_options);
|
||||
writer.write (output_layout, stream);
|
||||
|
||||
}
|
||||
|
||||
// Determine the output status based on the output top cell's emptyness
|
||||
|
||||
for (std::vector<unsigned int>::const_iterator l = output_layers.begin (); l != output_layers.end () && result; ++l) {
|
||||
result = output_layout.cell (output_top).bbox (*l).empty ();
|
||||
}
|
||||
|
||||
// @@@ TODO: print a nice summary unless "silent" is set
|
||||
|
||||
return result ? 0 : 1;
|
||||
}
|
||||
|
||||
|
|
@ -1,236 +0,0 @@
|
|||
|
||||
/*
|
||||
|
||||
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 "bdInit.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbWriter.h"
|
||||
#include "dbShapeProcessor.h"
|
||||
#include "tlString.h"
|
||||
|
||||
void
|
||||
syntax ()
|
||||
{
|
||||
printf ("Syntax: strmxor [-u <undersize>] [-topa <topcell-a>] [-topb <topcell-b>] [-oasis|-oas] [-gds2|-gds] <infile-a> <infile-b> [<outfile>]\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv [])
|
||||
{
|
||||
std::string topcell_a;
|
||||
std::string topcell_b;
|
||||
std::string infile_a;
|
||||
std::string infile_b;
|
||||
std::string outfile;
|
||||
double undersize = 0.0;
|
||||
bool format_set = false;
|
||||
std::string format;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
try {
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string o (argv[i]);
|
||||
if (o == "-u") {
|
||||
if (i < argc - 1) {
|
||||
++i;
|
||||
tl::from_string (argv[i], undersize);
|
||||
}
|
||||
} else if (o == "-topa") {
|
||||
if (i < argc - 1) {
|
||||
++i;
|
||||
topcell_a = argv[i];
|
||||
}
|
||||
} else if (o == "-topb") {
|
||||
if (i < argc - 1) {
|
||||
++i;
|
||||
topcell_b = argv[i];
|
||||
}
|
||||
} else if (o == "-oasis" || o == "-oas") {
|
||||
format_set = true;
|
||||
format = "OASIS";
|
||||
} else if (o == "-gds2" || o == "-gds") {
|
||||
format_set = true;
|
||||
format = "GDS2";
|
||||
} else if (o == "-h" || o == "-help" || o == "--help") {
|
||||
syntax ();
|
||||
return 0;
|
||||
} else if (argv[i][0] == '-') {
|
||||
throw tl::Exception("Unknown option: %s - use '-h' for help", (const char *) argv[i]);
|
||||
} else if (infile_a.empty ()) {
|
||||
infile_a = argv[i];
|
||||
} else if (infile_b.empty ()) {
|
||||
infile_b = argv[i];
|
||||
} else if (outfile.empty ()) {
|
||||
outfile = argv[i];
|
||||
} else {
|
||||
throw tl::Exception("Superfluous argument: %s - use '-h' for help", (const char *) argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (infile_a.empty () || infile_b.empty ()) {
|
||||
throw tl::Exception("Both input files must be specified");
|
||||
}
|
||||
|
||||
db::Manager m;
|
||||
db::Layout layout_a (&m);
|
||||
db::Layout layout_b (&m);
|
||||
|
||||
{
|
||||
tl::InputStream stream (infile_a);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout_a);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream stream (infile_b);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout_b);
|
||||
}
|
||||
|
||||
db::cell_index_type top_a;
|
||||
if (topcell_a.empty ()) {
|
||||
db::Layout::top_down_iterator t = layout_a.begin_top_down ();
|
||||
if (t == layout_a.end_top_cells ()) {
|
||||
throw tl::Exception ("Layout A (%s) does not have a top cell", infile_a);
|
||||
}
|
||||
top_a = *t++;
|
||||
if (t != layout_a.end_top_cells ()) {
|
||||
throw tl::Exception ("Layout A (%s) has multiple top cells", infile_a);
|
||||
}
|
||||
} else {
|
||||
std::pair<bool, db::cell_index_type> cn = layout_a.cell_by_name (topcell_a.c_str ());
|
||||
if (! cn.first) {
|
||||
throw tl::Exception ("Layout A (%s) does not have a topcell called '%s'", infile_a, topcell_a);
|
||||
}
|
||||
top_a = cn.second;
|
||||
}
|
||||
|
||||
db::cell_index_type top_b;
|
||||
if (topcell_b.empty ()) {
|
||||
db::Layout::top_down_iterator t = layout_b.begin_top_down ();
|
||||
if (t == layout_b.end_top_cells ()) {
|
||||
throw tl::Exception ("Layout B (%s) does not have a top cell", infile_b);
|
||||
}
|
||||
top_b = *t++;
|
||||
if (t != layout_b.end_top_cells ()) {
|
||||
throw tl::Exception ("Layout B (%s) has multiple top cells", infile_b);
|
||||
}
|
||||
} else {
|
||||
std::pair<bool, db::cell_index_type> cn = layout_b.cell_by_name (topcell_b.c_str ());
|
||||
if (! cn.first) {
|
||||
throw tl::Exception ("Layout B (%s) does not have a topcell called '%s'", infile_b, topcell_b);
|
||||
}
|
||||
top_b = cn.second;
|
||||
}
|
||||
|
||||
if (fabs (layout_a.dbu () - layout_b.dbu ()) > 1e-6) {
|
||||
throw tl::Exception("Input file database units differ (A:%g vs. B:%g)", layout_a.dbu (), layout_b.dbu ());
|
||||
}
|
||||
|
||||
std::map<db::LayerProperties, std::pair<int, int> > all_layers;
|
||||
for (unsigned int i = 0; i < layout_a.layers (); ++i) {
|
||||
if (layout_a.is_valid_layer (i)) {
|
||||
all_layers.insert (std::make_pair(layout_a.get_properties (i), std::make_pair(-1, -1))).first->second.first = int (i);
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < layout_b.layers (); ++i) {
|
||||
if (layout_b.is_valid_layer (i)) {
|
||||
all_layers.insert (std::make_pair(layout_b.get_properties (i), std::make_pair(-1, -1))).first->second.second = int (i);
|
||||
}
|
||||
}
|
||||
|
||||
db::Layout output;
|
||||
output.dbu (layout_a.dbu ());
|
||||
db::cell_index_type top_id = output.add_cell (layout_a.cell_name (top_a));
|
||||
|
||||
db::Coord us = db::coord_traits<db::Coord>::rounded (undersize / layout_a.dbu ());
|
||||
|
||||
db::ShapeProcessor sp;
|
||||
|
||||
size_t ndiff = 0;
|
||||
|
||||
for (std::map<db::LayerProperties, std::pair<int, int> >::const_iterator l = all_layers.begin (); l != all_layers.end (); ++l) {
|
||||
|
||||
int layer_id = output.insert_layer (l->first);
|
||||
|
||||
if (l->second.first >= 0 && l->second.second >= 0) {
|
||||
|
||||
sp.boolean (layout_a, layout_a.cell (top_a), l->second.first, layout_b, layout_b.cell (top_b), l->second.second,
|
||||
output.cell (top_id).shapes (layer_id), db::BooleanOp::Xor, true /*recursive*/);
|
||||
|
||||
sp.size (output, output.cell (top_id), layer_id, output.cell (top_id).shapes (layer_id), -us, (unsigned int) 2, true /*recursive*/);
|
||||
|
||||
} else if (l->second.first >= 0) {
|
||||
|
||||
sp.size (layout_a, layout_a.cell (top_a), l->second.first, output.cell (top_id).shapes (layer_id), -us, (unsigned int) 2, true /*recursive*/);
|
||||
|
||||
} else if (l->second.second >= 0) {
|
||||
|
||||
sp.size (layout_b, layout_b.cell (top_b), l->second.second, output.cell (top_id).shapes (layer_id), -us, (unsigned int) 2, true /*recursive*/);
|
||||
|
||||
}
|
||||
|
||||
size_t n = output.cell (top_id).shapes (layer_id).size ();
|
||||
// if (n > 0) {
|
||||
ndiff += n;
|
||||
tl::info << " " << l->first.to_string () << ": " << n;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
if (ndiff > 0) {
|
||||
tl::info << "----------------------------------------------------";
|
||||
tl::info << " Total differences: " << ndiff;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (! outfile.empty ()) {
|
||||
|
||||
db::SaveLayoutOptions options;
|
||||
options.set_format_from_filename (outfile);
|
||||
if (format_set) {
|
||||
options.set_format (format);
|
||||
}
|
||||
|
||||
db::Writer writer (options);
|
||||
tl::OutputStream file (outfile, tl::OutputStream::OM_Auto);
|
||||
writer.write (output, file);
|
||||
|
||||
}
|
||||
|
||||
} catch (std::exception &ex) {
|
||||
tl::error << ex.what ();
|
||||
return 1;
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
return 1;
|
||||
} catch (...) {
|
||||
tl::error << "unspecific error";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,13 +1,2 @@
|
|||
|
||||
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
|
||||
include($$PWD/../buddy_app.pri)
|
||||
|
|
|
|||
|
|
@ -533,3 +533,57 @@ TEST(8B)
|
|||
"Cell TRANS in a is renamed to SNART in b\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(9A)
|
||||
{
|
||||
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_ref9.gds";
|
||||
|
||||
char *argv[] = { "x", const_cast<char *> (input_a.c_str ()), const_cast<char *> (input_b.c_str ()) };
|
||||
|
||||
EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1);
|
||||
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 8/1 is not present in layout b, but in a\n"
|
||||
"Layouts differ\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(9B)
|
||||
{
|
||||
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_ref9.gds";
|
||||
|
||||
char *argv[] = { "x", "-l", const_cast<char *> (input_a.c_str ()), const_cast<char *> (input_b.c_str ()) };
|
||||
|
||||
EXPECT_EQ (strmcmp (sizeof (argv) / sizeof (argv[0]), argv), 1);
|
||||
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Texts differ for layer 8/1 in cell RINGO\n"
|
||||
"Not in b but in a:\n"
|
||||
" ('FB',r0 0,1800)\n"
|
||||
" ('OSC',r0 24560,1800)\n"
|
||||
" ('VDD',r0 0,2800)\n"
|
||||
" ('VSS',r0 0,0)\n"
|
||||
"Not in a but in b:\n"
|
||||
"Layouts differ\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue