DRC tests integrated now + refactoring

Refactoring:
* more consistent behavior of output redirection
* ut library was refactored and split into several
  .h/.cc
* concept of long runners introduced
* long runners can be skipped with "test_is_long_runner()"
* same for editable/non-editable mode tests
This commit is contained in:
Matthias Koefferlein 2017-08-23 23:19:36 +02:00
parent e5c6bd9e29
commit be1b007f2f
25 changed files with 2834 additions and 1692 deletions

View File

@ -4181,14 +4181,14 @@ CODE
@output_layout_file = nil
else
@output_layout = RBA::Layout::new
@output_cell = @output_layout.create_cell(cellname.to_s || "TOP")
@output_cell = cellname && @output_layout.create_cell(cellname.to_s)
@output_layout_file = arg
end
elsif arg.is_a?(RBA::Layout)
@output_layout = arg
@output_cell = @output_layout.create_cell(cellname.to_s || "TOP")
@output_cell = cellname && (@output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s))
@output_layout_file = nil
elsif arg.is_a?(RBA::Cell)

View File

@ -63,3 +63,37 @@ TEST(1)
this->compare_layouts (layout, au, ut::NoNormalization);
}
TEST(2)
{
lym::Macro drc;
drc.set_text (
"dbu 0.001\n"
"def compare(a, b, ex)\n"
" a = a.to_s\n"
" b = b.to_s\n"
" if a != b\n"
" raise(ex + \" (actual=#{a}, ref=#{b})\")\n"
" end\n"
"end\n"
"compare(0.1.um, 0.1, \"unexpected value when converting um\")\n"
"compare(0.1.micron, 0.1, \"unexpected value when converting micron\")\n"
"compare(0.1.um2, 0.1, \"unexpected value when converting um2\")\n"
"compare(0.1.mm2, 100000.0, \"unexpected value when converting mm2\")\n"
"compare(120.dbu, 0.12, \"unexpected value when converting dbu\")\n"
"compare((0.1.um + 120.dbu), 0.22, \"unexpected value when adding values\")\n"
"compare(0.1.mm, 100.0, \"unexpected value when converting mm\")\n"
"compare(1e-6.m, 1.0, \"unexpected value when converting m\")\n"
"compare(1.um, 1.0, \"unexpected value when converting integer um\")\n"
"compare(1.micron, 1.0, \"unexpected value when convering integer micron\")\n"
"compare(1.um2, 1.0, \"unexpected value when converting integer um2\")\n"
"compare(1.mm2, 1000000.0, \"unexpected value when converting integer mm2\")\n"
"compare((1.um + 120.dbu), 1.12, \"unexpected value when adding integer values\")\n"
"compare(1.mm, 1000.0, \"unexpected value when converting integer mm\")\n"
"compare(1.m, 1000000.0, \"unexpected value when converting integer m\")\n"
);
drc.set_interpreter (lym::Macro::DSLInterpreter);
drc.set_dsl_interpreter ("drc-dsl");
EXPECT_EQ (drc.run (), 0);
}

View File

@ -0,0 +1,142 @@
/*
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 "dbReader.h"
#include "lymMacro.h"
TEST(1)
{
std::string rs = ut::testsrc ();
rs += "/testdata/drc/drcSimpleTests_1.drc";
std::string au = ut::testsrc ();
au += "/testdata/drc/drcSimpleTests_au1.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$drc_test_source = nil\n"
"$drc_test_target = \"%s\"\n"
, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro drc;
drc.load_from (rs);
EXPECT_EQ (drc.run (), 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 rs = ut::testsrc ();
rs += "/testdata/drc/drcSimpleTests_2.drc";
std::string input = ut::testsrc ();
input += "/testdata/drc/drctest.gds";
std::string au = ut::testsrc ();
au += "/testdata/drc/drcSimpleTests_au2.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$drc_test_source = \"%s\"\n"
"$drc_test_target = \"%s\"\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro drc;
drc.load_from (rs);
EXPECT_EQ (drc.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
this->compare_layouts (layout, au, ut::NoNormalization);
}
TEST(3)
{
std::string rs = ut::testsrc ();
rs += "/testdata/drc/drcSimpleTests_3.drc";
std::string input = ut::testsrc ();
input += "/testdata/drc/drctest.gds";
std::string au = ut::testsrc ();
au += "/testdata/drc/drcSimpleTests_au3.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$drc_test_source = \"%s\"\n"
"$drc_test_target = \"%s\"\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro drc;
drc.load_from (rs);
EXPECT_EQ (drc.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
this->compare_layouts (layout, au, ut::NoNormalization);
}

View File

@ -0,0 +1,91 @@
/*
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 "dbReader.h"
#include "lymMacro.h"
void runtest (ut::TestBase *_this, int mode)
{
std::string rs = ut::testsrc ();
rs += "/testdata/drc/drcSuiteTests.drc";
std::string input = ut::testsrc ();
input += "/testdata/drc/drctest.gds";
std::string au = ut::testsrc ();
au += "/testdata/drc/drcSuiteTests_au";
au += tl::to_string (mode);
au += ".gds";
std::string output = _this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$drc_test_source = \"%s\"\n"
"$drc_test_target = \"%s\"\n"
"$drc_test_mode = %d\n"
, input, output, mode)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro drc;
drc.load_from (rs);
EXPECT_EQ (drc.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
_this->compare_layouts (layout, au, ut::NoNormalization);
}
TEST(1)
{
runtest (_this, 1);
}
TEST(2)
{
test_is_long_runner ();
runtest (_this, 2);
}
TEST(3)
{
test_is_long_runner ();
runtest (_this, 3);
}
TEST(4)
{
test_is_long_runner ();
runtest (_this, 4);
}

View File

@ -9,6 +9,8 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
drcBasicTests.cc \
drcSimpleTests.cc \
drcSuiteTests.cc \
INCLUDEPATH += ../drc ../../rdb ../../db ../../tl ../../gsi ../../lym ../../ut
DEPENDPATH += ../drc ../../rdb ../../db ../../tl ../../gsi ../../lym ../../ut

View File

@ -47,7 +47,7 @@ TEST(1_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -78,7 +78,7 @@ TEST(1_2)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -109,7 +109,7 @@ TEST(1_3)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -140,7 +140,7 @@ TEST(1_4)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -171,7 +171,7 @@ TEST(1_5)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -229,7 +229,7 @@ TEST(10_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -295,7 +295,7 @@ TEST(11_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -526,7 +526,7 @@ TEST(11_2)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -592,7 +592,7 @@ TEST(11_3)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -692,7 +692,7 @@ TEST(11_4)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -923,7 +923,7 @@ TEST(11_5)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1024,7 +1024,7 @@ TEST(11_6)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1067,7 +1067,7 @@ TEST(11_7)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1161,7 +1161,7 @@ TEST(12_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1211,7 +1211,7 @@ TEST(13_1)
db::LayerMap map = reader.read (layout);
EXPECT_EQ (map.to_string (), "layer_map('1/2 : \\'AA;L5A\\' (1/2)';'1/5 : \\'AA;L5A\\' (1/5)';'1/6 : \\'AA;L5A\\' (1/6)';'1/8 : \\'AA;L5A\\' (1/8)';'5/2 : \\'AA;L5A;H5A;E5A;I56A;E5L4\\' (5/2)';'5/5 : \\'AA;L5A;H5A;E5A;I56A;E5H4;E5I47\\' (5/5)';'5/6 : \\'AA;L5A;H5A;E5A;I56A;E5H4;E5I47\\' (5/6)';'5/8 : \\'AA;L5A;H5A;E5A;I56A;E5H4\\' (5/8)';'6/2 : \\'AA;H5A;I56A\\' (6/2)';'6/5 : \\'AA;H5A;I56A\\' (6/5)';'6/6 : \\'AA;H5A;I56A\\' (6/6)';'6/8 : \\'AA;H5A;I56A\\' (6/8)';'7/2 : \\'AA;H5A\\' (7/2)';'7/5 : \\'AA;H5A\\' (7/5)';'7/6 : \\'AA;H5A\\' (7/6)';'7/8 : \\'AA;H5A\\' (7/8)')")
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1261,7 +1261,7 @@ TEST(13_2)
db::LayerMap map = reader.read (layout);
EXPECT_EQ (map.to_string (), "layer_map('1/2 : \\'AA;L5A\\' (1/2)';'1/5 : \\'AA;L5A\\' (1/5)';'1/6 : \\'AA;L5A\\' (1/6)';'1/8 : \\'AA;L5A\\' (1/8)';'5/2 : \\'AA;L5A;H5A;E5A;I56A\\' (5/2)';'5/5 : \\'AA;L5A;H5A;E5A;I56A\\' (5/5)';'5/6 : \\'AA;L5A;H5A;E5A;I56A\\' (5/6)';'5/8 : \\'AA;L5A;H5A;E5A;I56A\\' (5/8)';'6/2 : \\'AA;H5A;I56A\\' (6/2)';'6/5 : \\'AA;H5A;I56A\\' (6/5)';'6/6 : \\'AA;H5A;I56A\\' (6/6)';'6/8 : \\'AA;H5A;I56A\\' (6/8)';'7/2 : \\'AA;H5A\\' (7/2)';'7/5 : \\'AA;H5A\\' (7/5)';'7/6 : \\'AA;H5A\\' (7/6)';'7/8 : \\'AA;H5A\\' (7/8)')");
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1327,7 +1327,7 @@ TEST(13_3)
db::LayerMap map = reader.read (layout);
EXPECT_EQ (map.to_string (), "layer_map('1/2 : \\'TAA;TL5A;AA;L5A\\' (1/2)';'1/5 : \\'TAA;TL5A;AA;L5A\\' (1/5)';'1/6 : \\'TAA;TL5A;AA;L5A\\' (1/6)';'1/8 : \\'TAA;TL5A;AA;L5A\\' (1/8)';'5/2 : \\'TAA;TL5A;TH5A;TE5A;TI56A;AA;L5A;H5A;E5A;I56A\\' (5/2)';'5/5 : \\'TAA;TL5A;TH5A;TE5A;TI56A;AA;L5A;H5A;E5A;I56A\\' (5/5)';'5/6 : \\'TAA;TL5A;TH5A;TE5A;TI56A;AA;L5A;H5A;E5A;I56A\\' (5/6)';'5/8 : \\'TAA;TL5A;TH5A;TE5A;TI56A;AA;L5A;H5A;E5A;I56A\\' (5/8)';'6/2 : \\'TAA;TH5A;TI56A;AA;H5A;I56A\\' (6/2)';'6/5 : \\'TAA;TH5A;TI56A;AA;H5A;I56A\\' (6/5)';'6/6 : \\'TAA;TH5A;TI56A;AA;H5A;I56A\\' (6/6)';'6/8 : \\'TAA;TH5A;TI56A;AA;H5A;I56A\\' (6/8)';'7/2 : \\'TAA;TH5A;AA;H5A\\' (7/2)';'7/5 : \\'TAA;TH5A;AA;H5A\\' (7/5)';'7/6 : \\'TAA;TH5A;AA;H5A\\' (7/6)';'7/8 : \\'TAA;TH5A;AA;H5A\\' (7/8)')");
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1393,7 +1393,7 @@ TEST(13_4)
db::LayerMap map = reader.read (layout);
EXPECT_EQ (map.to_string (), "layer_map('1/2 : \\'TAA;TL5A;AA;L5A\\' (1/2)';'1/5 : \\'TAA;TL5A;AA;L5A\\' (1/5)';'1/6 : \\'TAA;TL5A;AA;L5A\\' (1/6)';'1/8 : \\'TAA;TL5A;AA;L5A\\' (1/8)';'5/2 : \\'TAA;TL5A;TH5A;TE5A;TI56A;AA;L5A;H5A;E5A;I56A\\' (5/2)';'5/5 : \\'TAA;TL5A;TH5A;TE5A;TI56A;AA;L5A;H5A;E5A;I56A\\' (5/5)';'5/6 : \\'TAA;TL5A;TH5A;TE5A;TI56A;AA;L5A;H5A;E5A;I56A\\' (5/6)';'5/8 : \\'TAA;TL5A;TH5A;TE5A;TI56A;AA;L5A;H5A;E5A;I56A\\' (5/8)';'6/2 : \\'TAA;TH5A;TI56A;AA;H5A;I56A\\' (6/2)';'6/5 : \\'TAA;TH5A;TI56A;AA;H5A;I56A\\' (6/5)';'6/6 : \\'TAA;TH5A;TI56A;AA;H5A;I56A\\' (6/6)';'6/8 : \\'TAA;TH5A;TI56A;AA;H5A;I56A\\' (6/8)';'7/2 : \\'TAA;TH5A;AA;H5A\\' (7/2)';'7/5 : \\'TAA;TH5A;AA;H5A\\' (7/5)';'7/6 : \\'TAA;TH5A;AA;H5A\\' (7/6)';'7/8 : \\'TAA;TH5A;AA;H5A\\' (7/8)')");
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1436,7 +1436,7 @@ TEST(14_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1469,7 +1469,7 @@ TEST(2_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1504,7 +1504,7 @@ TEST(2_2)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1561,7 +1561,7 @@ TEST(2_4)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1618,7 +1618,7 @@ TEST(2_6)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1869,7 +1869,7 @@ TEST(3_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -1903,7 +1903,7 @@ TEST(3_10)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -2176,7 +2176,7 @@ TEST(3_12)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -2427,7 +2427,7 @@ TEST(3_2)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -2722,7 +2722,7 @@ TEST(3_5)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -2822,7 +2822,7 @@ TEST(3_9)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -2879,7 +2879,7 @@ TEST(4_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3008,7 +3008,7 @@ TEST(4_2)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3077,7 +3077,7 @@ TEST(5_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3113,7 +3113,7 @@ TEST(5_2)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3291,7 +3291,7 @@ TEST(5_3)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3354,7 +3354,7 @@ TEST(6_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3488,7 +3488,7 @@ TEST(7_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3540,7 +3540,7 @@ TEST(8_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3583,7 +3583,7 @@ TEST(8_2)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3626,7 +3626,7 @@ TEST(8_3)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3669,7 +3669,7 @@ TEST(8_4)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3712,7 +3712,7 @@ TEST(8_5)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3759,7 +3759,7 @@ TEST(8_6)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3802,7 +3802,7 @@ TEST(8_7)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3845,7 +3845,7 @@ TEST(8_8)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3945,7 +3945,7 @@ TEST(9_1)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -3984,7 +3984,7 @@ TEST(9_2)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -4036,7 +4036,7 @@ TEST(99)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)
@ -4053,7 +4053,7 @@ TEST(99)
try {
db::LayerMap map = reader.read (layout);
} catch (tl::Exception &ex) {
ut::print_error (ex.msg ());
tl::error << ex.msg ();
error = true;
}
EXPECT_EQ (error, false)

View File

@ -24,6 +24,7 @@
#include "tlEvents.h"
#include "utHead.h"
#include <memory>
// Object with event
class Observed

View File

@ -11,10 +11,14 @@ TEMPLATE = lib
# Input
HEADERS = \
utHead.h \
utCommon.h
utTestBase.h \
utTestConsole.h \
utCommon.h
SOURCES = \
utMain.cc \
utTestConsole.cc \
utTestBase.cc \
INCLUDEPATH = ../tl ../db ../gsi ../lay ../ext ../lib
DEPENDPATH = ../tl ../db ../gsi ../lay ../ext ../lib

View File

@ -24,482 +24,20 @@
#ifndef HDR_utHead
#define HDR_utHead
#include <vector>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include "utCommon.h"
#include "tlString.h"
#include "tlException.h"
#include "tlStaticObjects.h"
#include "dbStatic.h"
#include "dbTypes.h"
#include "gsiExpression.h"
#include "gsiInterpreter.h"
#include <QCoreApplication>
#include <QFileInfo>
namespace db {
class Layout;
class LayerMap;
}
namespace rba {
class RubyInterpreter;
}
namespace pya {
class PythonInterpreter;
}
#include "utTestBase.h"
#include "utTestConsole.h"
namespace ut {
extern tl::LogTee ctrl;
extern tl::LogTee noctrl;
/**
* @brief The unit test execution function
*/
UT_PUBLIC int main (int argc, char **argv);
/**
* @brief Prints a error message to the unit test output stream
*/
UT_PUBLIC void print_error (const std::string &s);
/**
* @brief A detailed diff printer
*/
UT_PUBLIC void write_detailed_diff (std::ostream &os, const std::string &subject, const std::string &ref);
/**
* @brief Returns true, if the test is run in verbose mode
* Verbose mode is enabled through the "-v" option
*/
UT_PUBLIC bool verbose ();
/**
* @brief Returns the Ruby interpreter
*/
UT_PUBLIC rba::RubyInterpreter *ruby_interpreter ();
/**
* @brief Returns the Python interpreter
*/
UT_PUBLIC pya::PythonInterpreter *python_interpreter ();
/**
* @brief Returns true, if the unit test is run in debug mode
* In debug mode, the unit tests shall offer information on how to fix the
* test. Specifically if layout compare is involved, it shall display the golden
* file name and the actual one and terminate to allow updating the files.
*/
UT_PUBLIC bool is_debug_mode ();
/**
* @brief Specifies the normalization mode for compare_layouts
*/
enum NormalizationMode
{
NoNormalization, // no normalization - take the test subject as it is
WriteGDS2, // normalize subject by writing to GDS2 and reading back
WriteOAS // normalize subject by writing to OASIS and reading back
};
/**
* @brief Gets the path of the test data
* This path is specified through the environment variable $TESTSRC
*/
UT_PUBLIC std::string testsrc ();
/**
* @brief Gets the path of the private test data
* This path is specified through the environment variable $TESTSRC and the
* private testdata directory. If no private test data is available, this
* method will throw a CancelException which makes the test skipped.
*/
UT_PUBLIC std::string testsrc_private ();
/**
* @brief A basic exception for the unit test framework
*/
struct Exception
: public tl::Exception
{
Exception (const std::string &msg)
: tl::Exception (msg)
{ }
};
/**
* @brief A utility class to capture the warning, error and info channels
*
* Instantiate this class inside a test. Then run the test and finally
* obtain the collected output with CaptureChannel::captured_text().
*/
class UT_PUBLIC CaptureChannel : public tl::Channel
{
public:
CaptureChannel ();
std::string captured_text () const
{
return m_text.str ();
}
void clear ()
{
m_text.str (std::string ());
}
protected:
virtual void puts (const char *s);
virtual void endl ();
virtual void end ();
virtual void begin ();
private:
std::ostringstream m_text;
};
/**
* @brief A generic compare operator
*/
template <class X, class Y>
inline bool equals (const X &a, const Y &b)
{
return a == b;
}
/**
* @brief A specialization of the compare operator for doubles
*/
UT_PUBLIC bool equals (double a, double b);
/**
* @brief Specialization of comparison of pointers vs. integers (specifically "0")
*/
template <class X>
inline bool equals (X *a, int b)
{
return a == (X *) size_t (b);
}
/**
* @brief A specialization of comparison of double vs "anything"
*/
template <class Y>
inline bool equals (double a, const Y &b)
{
return equals (a, double (b));
}
/**
* @brief A specialization of comparison of "anything" vs. double
*/
template <class X>
inline bool equals (const X &a, double b)
{
return equals (double (a), b);
}
/**
* @brief A specialization of the compare operator for const char *
*/
inline bool equals (const char *a, const char *b)
{
return equals (std::string (a), std::string (b));
}
/**
* @brief A specialization of the compare operator for std::string vs. const char *
*/
inline bool equals (const std::string &a, const char *b)
{
return equals (a, std::string (b));
}
/**
* @brief A specialization of the compare operator for std::string vs. const char *
*/
inline bool equals (const char *a, const std::string &b)
{
return equals (std::string (a), b);
}
/**
* @brief The base class for tests
*/
struct UT_PUBLIC TestBase
{
/**
* @brief Constructor
*/
TestBase (const std::string &file, const std::string &name);
/**
* @brief Destructor
*/
virtual ~TestBase () { }
/**
* @brief Actually runs the test
* @return True, if the test was successful
*/
bool do_test (const std::string &mode);
/**
* @brief Raises an exception with the given string
* This version prints the last checkpoint for reference.
*/
void raise (const std::string &s);
/**
* @brief Raises an exception with the given string, file and line number
*/
void raise (const std::string &file, int line, const std::string &s);
/**
* @brief Registers a checkpoint
*/
void checkpoint (const std::string &file, int line);
/**
* @brief Resets the checkpoints set
*/
void reset_checkpoint ();
/**
* @brief Compares a layout with a golden layout file
* @param layout The layout to compare
* @param au_file The golden file path
* @param norm The normalization mode (see NormalizationMode)
* @param tolerance A tolerance applied when comparing shapes in database units
* The layout is normalized by writing to a file and reading back
*/
void compare_layouts (const db::Layout &layout, const std::string &au_file, NormalizationMode norm = WriteGDS2, db::Coord tolerance = 0);
/**
* @brief Compares a layout with a golden layout file with layer mapping
* @param layout The layout to compare
* @param au_file The golden file path
* @param lmap The layer mapping object
* @param read_all_others If true, all other layers will be read too
* @param norm The normalization mode (see NormalizationMode)
* @param tolerance A tolerance applied when comparing shapes in database units
* The layout is normalized by writing to a file and reading back
*/
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
*/
const std::string &name () const
{
return m_test;
}
/**
* @brief Prepares a temporary file path
* @param fn The actual name of the file
* @return A path suitable for writing a temporary file
* The directory for the file will be created within this method.
*/
std::string tmp_file (const std::string &fn = "tmp") const;
/**
* @brief Removes all temporary files
*/
void remove_tmp_folder ();
/**
* @brief A generic diff printer
*/
template <class X, class Y>
void diff (const std::string &file, int line, const std::string &msg, const X &subject, const Y & /*ref*/)
{
std::ostringstream sstr;
sstr << msg << " (actual value is " << subject << ")";
raise (file, line, sstr.str ());
}
/**
* @brief A generic diff printer
*/
template <class X, class Y>
void detailed_diff (const std::string &file, int line, const std::string &msg, const X &subject, const Y &ref)
{
std::ostringstream sstr;
sstr << msg << std::endl;
ut::write_detailed_diff (sstr, tl::to_string (subject), tl::to_string (ref));
raise (file, line, sstr.str ());
}
/**
* @brief A diff printer for int vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, int subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for unsigned int vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, unsigned int subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for long vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, long subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for unsigned long vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, unsigned long subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for long long vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, long long subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for unsigned long long vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, unsigned long long subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for bool
*/
inline void diff (const std::string &file, int line, const std::string &msg, bool subject, bool ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for double
*/
inline void diff (const std::string &file, int line, const std::string &msg, double subject, double ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for strings
*/
inline void diff (const std::string &file, int line, const std::string &msg, const std::string &subject, const std::string &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for strings vs. const char *
*/
inline void diff (const std::string &file, int line, const std::string &msg, const std::string &subject, const char *ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for strings vs. const char *
*/
inline void diff (const std::string &file, int line, const std::string &msg, const char *subject, const std::string &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for C strings
*/
inline void diff (const std::string &file, int line, const std::string &msg, const char *subject, const char *ref)
{
diff (file, line, msg, std::string (subject), std::string (ref));
}
/**
* @brief Main entry point for the compare feature (EXPECT_EQ and EXPECT_NE)
*/
template <class T1, class T2>
void eq_helper (bool eq, const T1 &a, const T2 &b, const char *what_expr, const char *equals_expr, const char *file, int line)
{
if (ut::equals (a, b) != eq) {
std::ostringstream sstr;
sstr << what_expr << " does not equal " << equals_expr;
diff (file, line, sstr.str (), a, b);
}
}
private:
virtual void execute (ut::TestBase *_this) throw (tl::Exception) = 0;
std::string m_test;
std::string m_testdir;
// last checkpoint
std::string m_cp_file;
int m_cp_line;
bool m_any_failed;
QString m_testtmp;
};
/**
* @brief The registration facility for tests
*/
struct Registrar
{
static void reg (ut::TestBase *t)
{
if (! ms_instance) {
ms_instance = new Registrar ();
}
ms_instance->m_tests.push_back (t);
}
static Registrar *instance ()
{
return ms_instance;
}
const std::vector <ut::TestBase *> &tests () const
{
return m_tests;
}
private:
static Registrar *ms_instance;
Registrar () : m_tests () { }
std::vector <ut::TestBase *> m_tests;
};
} // namespace ut
#define TEST(NAME) \

File diff suppressed because it is too large Load Diff

458
src/ut/utTestBase.cc Normal file
View File

@ -0,0 +1,458 @@
/*
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 "utTestBase.h"
#include "utTestConsole.h"
#include "utHead.h"
#include "tlFileUtils.h"
#include "tlTimer.h"
#include "tlStream.h"
#include "dbLayout.h"
#include "dbStreamLayers.h"
#include "dbGDS2Writer.h"
#include "dbOASISWriter.h"
#include "dbReader.h"
#include "dbCommonReader.h"
#include "dbLayoutDiff.h"
#include "pya.h"
#include "rba.h"
#include <QDir>
namespace ut
{
// --------------------------------------------------------------------------------------
static bool s_verbose_flag = false;
static bool s_debug_mode = false;
static bool s_continue_flag = false;
bool verbose ()
{
return s_verbose_flag;
}
void set_verbose (bool f)
{
s_verbose_flag = f;
}
void set_continue_flag (bool f)
{
s_continue_flag = f;
}
bool is_debug_mode ()
{
return s_debug_mode;
}
void set_debug_mode (bool f)
{
s_debug_mode = f;
}
pya::PythonInterpreter *python_interpreter ()
{
pya::PythonInterpreter *ip = pya::PythonInterpreter::instance ();
tl_assert (ip != 0);
return ip;
}
rba::RubyInterpreter *ruby_interpreter ()
{
rba::RubyInterpreter *ip = rba::RubyInterpreter::instance ();
tl_assert (ip != 0);
return ip;
}
std::string testsrc ()
{
const char *ts = getenv ("TESTSRC");
if (! ts) {
throw tl::Exception ("TESTSRC undefined");
}
return ts;
}
std::string testsrc_private ()
{
QDir d (QDir (tl::to_qstring (ut::testsrc ())).filePath (QString::fromUtf8 ("private")));
if (! d.exists ()) {
throw tl::CancelException ();
}
return tl::to_string (d.path ());
}
std::string testtmp ()
{
// Ensures the test temp directory is present
const char *tt = getenv ("TESTTMP");
if (! tt) {
throw tl::Exception ("TESTTMP undefined");
}
return tt;
}
bool equals (double a, double b)
{
double m = fabs (0.5 * (a + b));
if (m < 1e-30) {
// resolution limit is 1e-30
return true;
} else {
double d = fabs (a - b);
// we consider two values equal for the purpose of unit tests if they have the
// same value within 1e-10 (0.00000001%).
return d < 1e-10 * m;
}
}
// TODO: move this to tlString.h
static std::string replicate (const char *s, size_t n)
{
std::string res;
res.reserve (strlen (s) * n);
while (n > 0) {
res += s;
--n;
}
return res;
}
// --------------------------------------------------------------------------------------
// TestBase implementation
ut::Registrar *ut::Registrar::ms_instance = 0;
TestBase::TestBase (const std::string &file, const std::string &name)
: m_editable (false), m_slow (false), m_cp_line (0), m_any_failed (false)
{
QFileInfo f (tl::to_qstring (file));
m_test = tl::to_string (f.baseName ()) + ":" + name;
m_testdir = tl::to_string (f.baseName ()) + "_" + name;
ut::Registrar::reg (this);
}
bool TestBase::do_test (bool editable, bool slow)
{
m_editable = editable;
m_slow = slow;
ut::ctrl << "<system-out>";
try {
// Ensures the test temp directory is present
QDir dir (tl::to_qstring (testtmp ()));
QDir tmpdir (dir.absoluteFilePath (tl::to_qstring (m_testdir)));
if (tmpdir.exists () && ! tl::rm_dir_recursive (tmpdir.absolutePath ())) {
throw tl::Exception ("Unable to clean temporary dir: " + tl::to_string (tmpdir.absolutePath ()));
}
if (! dir.mkpath (tl::to_qstring (m_testdir))) {
throw tl::Exception ("Unable to create path for temporary files: " + tl::to_string (tmpdir.absolutePath ()));
}
dir.cd (tl::to_qstring (m_testdir));
m_testtmp = dir.absolutePath ();
static std::string testname_value;
static std::string testtmp_value;
putenv (const_cast<char *> ("TESTNAME="));
testname_value = std::string ("TESTNAME=") + m_test;
putenv (const_cast<char *> (testname_value.c_str ()));
putenv (const_cast<char *> ("TESTTMP_WITH_NAME="));
testtmp_value = std::string ("TESTTMP_WITH_NAME=") + m_testtmp.toUtf8().constData();
putenv (const_cast<char *> (testtmp_value.c_str ()));
reset_checkpoint ();
tl::Timer timer;
timer.start();
execute (this);
timer.stop();
m_testtmp.clear ();
ut::ctrl << "</system-out>";
ut::noctrl << "Time: " << timer.sec_wall () << "s (wall) " << timer.sec_user () << "s (user) " << timer.sec_sys () << "s (sys)";
ut::ctrl << "<x-testcase-times wall=\"" << timer.sec_wall () << "\" user=\"" << timer.sec_user () << "\" sys=\"" << timer.sec_sys () << "\"/>";
} catch (...) {
ut::ctrl << "</system-out>";
throw;
}
return (!m_any_failed);
}
std::string TestBase::tmp_file (const std::string &fn) const
{
tl_assert (! m_testtmp.isEmpty ());
QDir dir (m_testtmp);
return tl::to_string (dir.absoluteFilePath (tl::to_qstring (fn)));
}
/**
* @brief Recursively empties a directory
*/
static void empty_dir (QDir dir)
{
QStringList entries = dir.entryList (QDir::AllEntries | QDir::NoDotAndDotDot);
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
QString epath = dir.absoluteFilePath (*e);
if (QFileInfo (epath).isDir ()) {
empty_dir (QDir (epath));
dir.rmdir (*e);
} else if (! dir.remove (*e)) {
throw tl::Exception ("Unable to remove file or directory: " + tl::to_string (dir.filePath (*e)));
}
}
}
void TestBase::remove_tmp_folder ()
{
// Ensures the test temp directory is present
QDir dir (tl::to_qstring (testtmp ()));
if (dir.cd (tl::to_qstring (m_test))) {
empty_dir (dir);
dir.cdUp ();
if (! dir.rmdir (tl::to_qstring (m_test))) {
throw tl::Exception ("Unable to remove directory: " + tl::to_string (dir.filePath (tl::to_qstring (m_test))));
}
}
}
void TestBase::checkpoint (const std::string &file, int line)
{
m_cp_file = file;
m_cp_line = line;
}
void TestBase::reset_checkpoint ()
{
m_cp_file = std::string ();
m_cp_line = 0;
}
void TestBase::raise (const std::string &file, int line, const std::string &msg)
{
std::ostringstream sstr;
sstr << file << ", line " << line << ": " << msg;
if (s_continue_flag) {
tl::error << sstr.str ();
m_any_failed = true;
} else {
throw ut::Exception (sstr.str ());
}
}
void TestBase::raise (const std::string &msg)
{
std::ostringstream sstr;
if (m_cp_line > 0) {
sstr << "(last checkpoint: " << m_cp_file << ", line " << m_cp_line << "): ";
}
sstr << msg;
if (s_continue_flag) {
tl::error << sstr.str ();
m_any_failed = true;
} else {
throw ut::Exception (sstr.str ());
}
}
void TestBase::test_is_editable_only ()
{
if (!m_editable) {
throw tl::CancelException ();
}
}
void TestBase::test_is_non_editable_only ()
{
if (m_editable) {
throw tl::CancelException ();
}
}
void TestBase::test_is_long_runner ()
{
if (!m_slow) {
throw tl::CancelException ();
}
}
void TestBase::compare_layouts (const db::Layout &layout, const std::string &au_file, NormalizationMode norm, db::Coord tolerance)
{
compare_layouts (layout, au_file, db::LayerMap (), true, norm, tolerance);
}
void TestBase::compare_layouts (const db::Layout &layout, const std::string &au_file, const db::LayerMap &lm, bool read_other_layers, NormalizationMode norm, db::Coord tolerance)
{
// normalize the layout by writing to GDS and reading from ..
// generate a "unique" name ...
unsigned int hash = 0;
for (const char *cp = au_file.c_str (); *cp; ++cp) {
hash = (hash << 4) ^ (hash >> 4) ^ ((unsigned int) *cp);
}
std::string tmp_file;
if (norm == WriteGDS2) {
tmp_file = ut::TestBase::tmp_file (tl::sprintf ("tmp_%x.gds", hash));
tl::OutputStream stream (tmp_file.c_str ());
db::GDS2Writer writer;
db::SaveLayoutOptions options;
writer.write (const_cast<db::Layout &> (layout), stream, options);
} else {
tmp_file = ut::TestBase::tmp_file (tl::sprintf ("tmp_%x.oas", hash));
tl::OutputStream stream (tmp_file.c_str ());
db::OASISWriter writer;
db::SaveLayoutOptions options;
writer.write (const_cast<db::Layout &> (layout), stream, options);
}
const db::Layout *subject = 0;
db::Layout layout2;
if (norm != NoNormalization) {
// read all layers from the original layout, so the layer table is the same
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
layout2.insert_layer ((*l).first, *(*l).second);
}
tl::InputStream stream (tmp_file);
db::Reader reader (stream);
reader.read (layout2);
subject = &layout2;
} else {
subject = &layout;
}
bool equal = false;
bool any = false;
int n = 0;
for ( ; ! equal; ++n) {
db::Layout layout_au;
// read all layers from the original layout, so the layer table is the same
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
layout_au.insert_layer ((*l).first, *(*l).second);
}
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lm;
options.get_options<db::CommonReaderOptions> ().create_other_layers = read_other_layers;
std::string fn = au_file;
if (n > 0) {
fn += tl::sprintf (".%d", n);
}
if (QFileInfo (tl::to_qstring (fn)).exists ()) {
if (n == 1 && any) {
throw tl::Exception (tl::sprintf ("Inconsistent reference variants for %s: there can be either variants (.1,.2,... suffix) or a single file (without suffix)", au_file));
}
any = true;
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (layout_au, options);
equal = db::compare_layouts (*subject, layout_au, (n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose) | db::layout_diff::f_flatten_array_insts /*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/, tolerance, 100 /*max diff lines*/);
if (equal && n > 0) {
tl::info << tl::sprintf ("Found match on golden reference variant %s", fn);
}
} else if (n > 0) {
if (! any) {
tl::warn << tl::sprintf ("No golden data found (%s)", au_file);
}
break;
}
}
if (! equal) {
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" : "")));
}
}
void TestBase::write_detailed_diff (std::ostream &os, const std::string &subject, const std::string &ref)
{
os << replicate (" ", TestConsole::instance ()->indent ()) << "Actual value is: " << tl::to_string (subject) << std::endl
<< replicate (" ", TestConsole::instance ()->indent ()) << "Reference value is: " << tl::to_string (ref) << std::endl
;
}
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 ())));
}
}
}

498
src/ut/utTestBase.h Normal file
View File

@ -0,0 +1,498 @@
/*
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
*/
#ifndef HDR_utTestBase
#define HDR_utTestBase
#include "utCommon.h"
#include "dbTypes.h"
#include "tlException.h"
#include "tlString.h"
#include <string>
#include <vector>
#include <sstream>
#include <QString>
namespace db
{
class Layout;
class LayerMap;
}
namespace rba
{
class RubyInterpreter;
}
namespace pya
{
class PythonInterpreter;
}
namespace ut
{
/**
* @brief Returns true, if the test is run in verbose mode
* Verbose mode is enabled through the "-v" option
*/
UT_PUBLIC bool verbose ();
/**
* @brief Sets verbose mode
*/
UT_PUBLIC void set_verbose (bool v);
/**
* @brief Enables or disables "continue" mode
* In continue mode, the execution will proceed even in case of an error.
*/
UT_PUBLIC void set_continue_flag (bool f);
/**
* @brief Returns the Ruby interpreter
*/
UT_PUBLIC rba::RubyInterpreter *ruby_interpreter ();
/**
* @brief Returns the Python interpreter
*/
UT_PUBLIC pya::PythonInterpreter *python_interpreter ();
/**
* @brief Returns true, if the unit test is run in debug mode
* In debug mode, the unit tests shall offer information on how to fix the
* test. Specifically if layout compare is involved, it shall display the golden
* file name and the actual one and terminate to allow updating the files.
*/
UT_PUBLIC bool is_debug_mode ();
/**
* @brief Enables or disables debug mode
*/
UT_PUBLIC void set_debug_mode (bool f);
/**
* @brief Gets the path of the test data
* This path is specified through the environment variable $TESTSRC
*/
UT_PUBLIC std::string testsrc ();
/**
* @brief Gets the path of the private test data
* This path is specified through the environment variable $TESTSRC and the
* private testdata directory. If no private test data is available, this
* method will throw a CancelException which makes the test skipped.
*/
UT_PUBLIC std::string testsrc_private ();
/**
* @brief Gets the path to the temporary data
* This path is specified through the environment variable $TESTTMP
*/
UT_PUBLIC std::string testtmp ();
/**
* @brief A basic exception for the unit test framework
*/
struct Exception
: public tl::Exception
{
Exception (const std::string &msg)
: tl::Exception (msg)
{ }
};
/**
* @brief Specifies the normalization mode for compare_layouts
*/
enum NormalizationMode
{
NoNormalization, // no normalization - take the test subject as it is
WriteGDS2, // normalize subject by writing to GDS2 and reading back
WriteOAS // normalize subject by writing to OASIS and reading back
};
/**
* @brief A generic compare operator
*/
template <class X, class Y>
inline bool equals (const X &a, const Y &b)
{
return a == b;
}
/**
* @brief A specialization of the compare operator for doubles
*/
UT_PUBLIC bool equals (double a, double b);
/**
* @brief Specialization of comparison of pointers vs. integers (specifically "0")
*/
template <class X>
inline bool equals (X *a, int b)
{
return a == (X *) size_t (b);
}
/**
* @brief A specialization of comparison of double vs "anything"
*/
template <class Y>
inline bool equals (double a, const Y &b)
{
return equals (a, double (b));
}
/**
* @brief A specialization of comparison of "anything" vs. double
*/
template <class X>
inline bool equals (const X &a, double b)
{
return equals (double (a), b);
}
/**
* @brief A specialization of the compare operator for const char *
*/
inline bool equals (const char *a, const char *b)
{
return equals (std::string (a), std::string (b));
}
/**
* @brief A specialization of the compare operator for std::string vs. const char *
*/
inline bool equals (const std::string &a, const char *b)
{
return equals (a, std::string (b));
}
/**
* @brief A specialization of the compare operator for std::string vs. const char *
*/
inline bool equals (const char *a, const std::string &b)
{
return equals (std::string (a), b);
}
/**
* @brief The base class for tests
*/
struct UT_PUBLIC TestBase
{
/**
* @brief Constructor
*/
TestBase (const std::string &file, const std::string &name);
/**
* @brief Destructor
*/
virtual ~TestBase () { }
/**
* @brief Actually runs the test
* @return True, if the test was successful
*/
bool do_test (bool editable, bool slow);
/**
* @brief Indicates that the test is a long runner
* In this case the test is skipped unless in slow mode.
*/
void test_is_long_runner ();
/**
* @brief Indicates that the test is a test that should run in editable mode only.
* In this case the test is skipped unless in editable mode.
*/
void test_is_editable_only ();
/**
* @brief Indicates that the test is a test that should run in non-editable mode only.
* In this case the test is skipped unless in non-editable mode.
*/
void test_is_non_editable_only ();
/**
* @brief Raises an exception with the given string
* This version prints the last checkpoint for reference.
*/
void raise (const std::string &s);
/**
* @brief Raises an exception with the given string, file and line number
*/
void raise (const std::string &file, int line, const std::string &s);
/**
* @brief Registers a checkpoint
*/
void checkpoint (const std::string &file, int line);
/**
* @brief Resets the checkpoints set
*/
void reset_checkpoint ();
/**
* @brief Compares a layout with a golden layout file
* @param layout The layout to compare
* @param au_file The golden file path
* @param norm The normalization mode (see NormalizationMode)
* @param tolerance A tolerance applied when comparing shapes in database units
* The layout is normalized by writing to a file and reading back
*/
void compare_layouts (const db::Layout &layout, const std::string &au_file, NormalizationMode norm = WriteGDS2, db::Coord tolerance = 0);
/**
* @brief Compares a layout with a golden layout file with layer mapping
* @param layout The layout to compare
* @param au_file The golden file path
* @param lmap The layer mapping object
* @param read_all_others If true, all other layers will be read too
* @param norm The normalization mode (see NormalizationMode)
* @param tolerance A tolerance applied when comparing shapes in database units
* The layout is normalized by writing to a file and reading back
*/
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
*/
const std::string &name () const
{
return m_test;
}
/**
* @brief Prepares a temporary file path
* @param fn The actual name of the file
* @return A path suitable for writing a temporary file
* The directory for the file will be created within this method.
*/
std::string tmp_file (const std::string &fn = "tmp") const;
/**
* @brief Removes all temporary files
*/
void remove_tmp_folder ();
/**
* @brief A generic diff printer
*/
template <class X, class Y>
void diff (const std::string &file, int line, const std::string &msg, const X &subject, const Y & /*ref*/)
{
std::ostringstream sstr;
sstr << msg << " (actual value is " << subject << ")";
raise (file, line, sstr.str ());
}
/**
* @brief A generic diff printer
*/
template <class X, class Y>
void detailed_diff (const std::string &file, int line, const std::string &msg, const X &subject, const Y &ref)
{
std::ostringstream sstr;
sstr << msg << std::endl;
write_detailed_diff (sstr, tl::to_string (subject), tl::to_string (ref));
raise (file, line, sstr.str ());
}
/**
* @brief A diff printer for int vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, int subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for unsigned int vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, unsigned int subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for long vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, long subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for unsigned long vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, unsigned long subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for long long vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, long long subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for unsigned long long vs. something
*/
template <class Y>
void diff (const std::string &file, int line, const std::string &msg, unsigned long long subject, const Y &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for bool
*/
inline void diff (const std::string &file, int line, const std::string &msg, bool subject, bool ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for double
*/
inline void diff (const std::string &file, int line, const std::string &msg, double subject, double ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for strings
*/
inline void diff (const std::string &file, int line, const std::string &msg, const std::string &subject, const std::string &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for strings vs. const char *
*/
inline void diff (const std::string &file, int line, const std::string &msg, const std::string &subject, const char *ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for strings vs. const char *
*/
inline void diff (const std::string &file, int line, const std::string &msg, const char *subject, const std::string &ref)
{
detailed_diff (file, line, msg, subject, ref);
}
/**
* @brief A diff printer for C strings
*/
inline void diff (const std::string &file, int line, const std::string &msg, const char *subject, const char *ref)
{
diff (file, line, msg, std::string (subject), std::string (ref));
}
/**
* @brief Main entry point for the compare feature (EXPECT_EQ and EXPECT_NE)
*/
template <class T1, class T2>
void eq_helper (bool eq, const T1 &a, const T2 &b, const char *what_expr, const char *equals_expr, const char *file, int line)
{
if (ut::equals (a, b) != eq) {
std::ostringstream sstr;
sstr << what_expr << " does not equal " << equals_expr;
diff (file, line, sstr.str (), a, b);
}
}
private:
virtual void execute (ut::TestBase *_this) throw (tl::Exception) = 0;
void write_detailed_diff (std::ostream &os, const std::string &subject, const std::string &ref);
bool m_editable, m_slow;
std::string m_test;
std::string m_testdir;
// last checkpoint
std::string m_cp_file;
int m_cp_line;
bool m_any_failed;
QString m_testtmp;
};
/**
* @brief The registration facility for tests
*/
struct Registrar
{
static void reg (ut::TestBase *t)
{
if (! ms_instance) {
ms_instance = new Registrar ();
}
ms_instance->m_tests.push_back (t);
}
static Registrar *instance ()
{
return ms_instance;
}
const std::vector <ut::TestBase *> &tests () const
{
return m_tests;
}
private:
static Registrar *ms_instance;
Registrar () : m_tests () { }
std::vector <ut::TestBase *> m_tests;
};
}
#endif

412
src/ut/utTestConsole.cc Normal file
View File

@ -0,0 +1,412 @@
/*
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 "utTestConsole.h"
#include "utHead.h"
#include "rba.h"
#include "pya.h"
#include <unistd.h>
#if !defined(_WIN32)
# include <sys/ioctl.h>
# include <dlfcn.h>
#endif
#if defined(_WIN32)
# include <Windows.h>
#endif
namespace ut
{
// ------------------------------------------------
// CaptureChannel implementation
CaptureChannel::CaptureChannel ()
{
tl::info.add (this, false);
tl::error.add (this, false);
tl::warn.add (this, false);
}
void CaptureChannel::puts (const char *s)
{
m_text << s;
}
void CaptureChannel::endl ()
{
m_text << "\n";
}
void CaptureChannel::end ()
{
// .. nothing yet ..
}
void CaptureChannel::begin ()
{
// .. nothing yet ..
}
// ------------------------------------------------
// tl::Channel implementations for redirecting the log output
class InfoChannel : public tl::Channel
{
public:
InfoChannel (int verbosity)
: m_verbosity (verbosity)
{
// .. nothing yet ..
}
protected:
virtual void puts (const char *s)
{
if (tl::verbosity () >= m_verbosity) {
TestConsole::instance ()->basic_write (s);
}
}
virtual void endl ()
{
if (tl::verbosity () >= m_verbosity) {
TestConsole::instance ()->basic_write ("\n");
}
}
virtual void end ()
{
TestConsole::instance ()->flush ();
}
virtual void begin ()
{
// .. nothing yet ..
}
private:
int m_verbosity;
};
class WarningChannel : public tl::Channel
{
public:
WarningChannel ()
{
// .. nothing yet ..
}
protected:
virtual void puts (const char *s)
{
TestConsole::instance ()->basic_write (s);
}
virtual void endl ()
{
TestConsole::instance ()->basic_write ("\n");
}
virtual void end ()
{
TestConsole::instance ()->end ();
TestConsole::instance ()->flush ();
}
virtual void begin ()
{
TestConsole::instance ()->begin_warn ();
}
};
class ErrorChannel : public tl::Channel
{
public:
ErrorChannel ()
{
// .. nothing yet ..
}
protected:
virtual void puts (const char *s)
{
TestConsole::instance ()->basic_write (s);
}
virtual void endl ()
{
TestConsole::instance ()->basic_write ("\n");
}
virtual void end ()
{
TestConsole::instance ()->end ();
TestConsole::instance ()->flush ();
}
virtual void begin ()
{
TestConsole::instance ()->begin_error ();
}
};
class CtrlChannel : public tl::Channel
{
public:
CtrlChannel (bool with_xml)
: m_with_xml (with_xml)
{
// .. nothing yet ..
}
protected:
virtual void puts (const char *s)
{
if (m_with_xml == TestConsole::instance ()->xml_format ()) {
TestConsole::instance ()->raw_write (s);
}
}
virtual void endl ()
{
if (m_with_xml == TestConsole::instance ()->xml_format ()) {
TestConsole::instance ()->raw_write ("\n");
}
}
virtual void end ()
{
if (m_with_xml == TestConsole::instance ()->xml_format ()) {
TestConsole::instance ()->end ();
TestConsole::instance ()->flush ();
}
}
virtual void begin ()
{
if (m_with_xml == TestConsole::instance ()->xml_format ()) {
TestConsole::instance ()->begin_info ();
}
}
private:
bool m_with_xml;
};
// ------------------------------------------------
// TestConsole implementation
const char *ANSI_RED = "\033[31;1m";
const char *ANSI_BLUE = "\033[34m";
const char *ANSI_GREEN = "\033[32m";
const char *ANSI_RESET = "\033[0m";
TestConsole::TestConsole (FILE *file, bool xml_format)
: m_file (file), m_xml_format (xml_format), m_col (0), m_max_col (250), m_columns (50), m_rows (0), m_is_tty (false)
{
ms_instance = this;
m_indent = 4;
m_is_tty = isatty (fileno (file)) && ! xml_format;
#if !defined(_WIN32)
if (m_is_tty) {
struct winsize ws;
ioctl (fileno (stdout), TIOCGWINSZ, &ws);
m_columns = std::max (0, (int) ws.ws_col);
m_rows = std::max (0, (int) ws.ws_row);
}
#endif
redirect ();
}
TestConsole::~TestConsole ()
{
restore ();
if (ms_instance == this) {
ms_instance = 0;
}
}
void
TestConsole::write_str (const char *text, output_stream os)
{
if (os == OS_stderr) {
begin_error ();
basic_write (text);
end ();
} else {
basic_write (text);
}
}
void
TestConsole::raw_write (const char *text)
{
fputs (text, m_file);
}
void
TestConsole::flush ()
{
fflush (m_file);
}
void
TestConsole::begin_error ()
{
if (m_is_tty) {
fputs (ANSI_RED, m_file);
}
}
void
TestConsole::begin_info ()
{
if (m_is_tty) {
fputs (ANSI_GREEN, m_file);
}
}
void
TestConsole::begin_warn ()
{
if (m_is_tty) {
fputs (ANSI_BLUE, m_file);
}
}
void
TestConsole::end ()
{
if (m_is_tty) {
fputs (ANSI_RESET, m_file);
}
}
void
TestConsole::basic_write (const char *s)
{
if (m_xml_format) {
for (const char *cp = s; *cp; ++cp) {
if (*cp == '&') {
fputs ("&amp;", m_file);
} else if (*cp == '<') {
fputs ("&lt;", m_file);
} else if (*cp == '>') {
fputs ("&gt;", m_file);
} else {
fputc (*cp, m_file);
}
}
} else {
// line length limitation - this assumes we are always printing to the same terminal
// or we don't mix stderr/stdout.
const char *cp;
for (cp = s; *cp; ++cp) {
if (*cp == '\n' || *cp == '\r') {
m_col = 0;
fputc (*cp, m_file);
} else {
if (m_col == 0) {
for (int i = 0; i < m_indent; ++i) {
fputc (' ', m_file);
}
m_col = m_indent;
}
if (m_col > m_max_col) {
// ignore char
} else if (m_col == m_max_col) {
fputs (" ...", m_file);
++m_col;
} else if (*cp == '\033') {
// skip ANSI escape sequences (no increment of s_col)
const char *cpend = cp + 1;
if (*cpend == '[') {
++cpend;
while (*cpend && *cpend != 'm') {
++cpend;
}
if (*cpend) {
++cpend;
}
}
while (cp != cpend) {
fputc (*cp++, m_file);
}
--cp;
} else {
fputc (*cp, m_file);
++m_col;
}
}
}
}
}
void
TestConsole::redirect ()
{
// redirect the log channels
tl::warn.clear ();
tl::warn.add (new ut::WarningChannel (), true);
tl::info.clear ();
tl::info.add (new ut::InfoChannel (0), true);
tl::log.clear ();
tl::log.add (new ut::InfoChannel (10), true);
tl::error.clear ();
tl::error.add (new ut::ErrorChannel (), true);
ut::ruby_interpreter ()->push_console (this);
ut::python_interpreter ()->push_console (this);
}
void
TestConsole::restore ()
{
// TODO: we should basically restore the original channels
tl::warn.clear ();
tl::info.clear ();
tl::log.clear ();
tl::error.clear ();
ut::ruby_interpreter ()->remove_console (this);
ut::python_interpreter ()->remove_console (this);
}
TestConsole *TestConsole::ms_instance = 0;
tl::LogTee noctrl (new CtrlChannel (false), true);
tl::LogTee ctrl (new CtrlChannel (true), true);
}

141
src/ut/utTestConsole.h Normal file
View File

@ -0,0 +1,141 @@
/*
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
*/
#ifndef HDR_utTestConsole
#define HDR_utTestConsole
#include "utCommon.h"
#include "tlLog.h"
#include "gsiInterpreter.h"
#include <cstdio>
#include <sstream>
namespace ut
{
/**
* @brief A utility class to capture the warning, error and info channels
*
* Instantiate this class inside a test. Then run the test and finally
* obtain the collected output with CaptureChannel::captured_text().
*/
class UT_PUBLIC CaptureChannel : public tl::Channel
{
public:
CaptureChannel ();
std::string captured_text () const
{
return m_text.str ();
}
void clear ()
{
m_text.str (std::string ());
}
protected:
virtual void puts (const char *s);
virtual void endl ();
virtual void end ();
virtual void begin ();
private:
std::ostringstream m_text;
};
/**
* @brief Redirects the interpreter output and serves as a general output device
*/
class TestConsole
: public gsi::Console
{
public:
static TestConsole *instance ()
{
tl_assert (ms_instance != 0);
return ms_instance;
}
TestConsole (FILE *file, bool xml_format);
~TestConsole ();
int indent () const
{
return m_indent;
}
bool xml_format () const
{
return m_xml_format;
}
void write_str (const char *text, output_stream os);
void raw_write (const char *text);
virtual void flush ();
virtual bool is_tty ()
{
// NOTE: this assumes we are delivering to stdout
return m_is_tty;
}
virtual int columns ()
{
return std::max (m_columns - m_indent, 0);
}
virtual int rows ()
{
return m_rows;
}
int real_columns ()
{
return m_columns;
}
void begin_error ();
void begin_info ();
void begin_warn ();
void end ();
void basic_write (const char *s);
private:
FILE *m_file;
bool m_xml_format;
int m_col;
int m_max_col;
int m_columns, m_rows;
bool m_is_tty;
int m_indent;
static TestConsole *ms_instance;
void redirect ();
void restore ();
};
}
#endif

21
testdata/drc/drcSimpleTests_1.drc vendored Normal file
View File

@ -0,0 +1,21 @@
dbu 0.001
target($drc_test_target, "TOP")
x = polygon_layer
x.is_empty? == true || raise("unexpected value")
x.is_box? == false || raise("unexpected value")
x.insert(box(4.0, 0, 4.7, 0.7))
x.is_empty? == false || raise("unexpected value")
x.is_box? == true || raise("unexpected value")
x.insert(polygon([ p(0, 0), p(2.0, 0), p(1.0, 1.0) ]))
x.insert(polygon([ p(0, -5.0), p(2.0, -5.0), p(1.0, -6.0) ]))
x.insert(path([ p(0, -2), p(2.0, -2) ], 0.2))
x.is_box? == false || raise("unexpected value")
x.output(10, 0)
y = polygon_layer
y.insert(polygon([ p(0, 0), p(0, 1.0), p(2.0, 1.0), p(2.0, 2.0), p(1.0, 2.0), p(1.0, 0) ]))
y.output(11, 0)

90
testdata/drc/drcSimpleTests_2.drc vendored Normal file
View File

@ -0,0 +1,90 @@
target($drc_test_target, "TOP")
source($drc_test_source, "TOP")
a1 = input(1)
b1 = input(2)
c1 = input(3)
a1.output(1, 0)
b1.output(2, 0)
c1.output(3, 0)
c1.rounded_corners(0.5, 0.5, 16).output(1010, 0)
c1.smoothed(1.5).output(1011, 0)
a1.texts.output(1020, 0)
a1.texts("A*").output(1021, 0)
a1.texts(text("A*")).output(1022, 0)
a1.texts(pattern("A*")).output(1023, 0)
a1.texts(pattern("A*"), as_dots).extended(0.05, 0.05, 0.05, 0.05).output(1024, 0)
a1.texts(pattern("A*"), as_boxes).output(1025, 0)
a1.middle.sized(0.05).output(1030, 0)
a1.middle(as_dots).extended(0.05, 0.05, 0.05, 0.05).output(1031, 0)
a1.middle(as_boxes).sized(0.05).output(1032, 0)
a1.extent_refs(0.5, 0.5).sized(0.05).output(1040, 0)
a1.extent_refs(:center).sized(0.05).output(1040, 1)
a1.extent_refs(:c).sized(0.05).output(1040, 2)
a1.extent_refs(:bottom).sized(0.05).output(1041, 0)
a1.extent_refs(:b).sized(0.05).output(1041, 1)
a1.extent_refs(:b, as_edges).extended(0.05, 0.05, 0.05, 0.05).output(1041, 2)
a1.extent_refs(:top).sized(0.05).output(1042, 0)
a1.extent_refs(:t).sized(0.05).output(1042, 1)
a1.extent_refs(:left).sized(0.05).output(1043, 0)
a1.extent_refs(:l).sized(0.05).output(1043, 1)
a1.extent_refs(:right).sized(0.05).output(1044, 0)
a1.extent_refs(:r).sized(0.05).output(1044, 1)
a1.extent_refs(:bottom_left).sized(0.05).output(1045, 0)
a1.extent_refs(:bl).sized(0.05).output(1045, 1)
a1.extent_refs(:bottom_center).sized(0.05).output(1046, 0)
a1.extent_refs(:bc).sized(0.05).output(1046, 1)
a1.extent_refs(:bottom_right).sized(0.05).output(1047, 0)
a1.extent_refs(:br).sized(0.05).output(1047, 1)
a1.extent_refs(:top_left).sized(0.05).output(1048, 0)
a1.extent_refs(:tl).sized(0.05).output(1048, 1)
a1.extent_refs(:top_center).sized(0.05).output(1049, 0)
a1.extent_refs(:tc).sized(0.05).output(1049, 1)
a1.extent_refs(:top_right).sized(0.05).output(1050, 0)
a1.extent_refs(:tr).sized(0.05).output(1050, 1)
a1.extent_refs(:left_center).sized(0.05).output(1051, 0)
a1.extent_refs(:lc).sized(0.05).output(1051, 1)
a1.extent_refs(:right_center).sized(0.05).output(1052, 0)
a1.extent_refs(:rc).sized(0.05).output(1052, 1)
a1.extent_refs(0.25, 0.5, 0.5, 0.75).output(1053, 0)
a1.corners.sized(0.05).output(1060, 0)
a1.corners(-90.0, as_boxes).sized(0.05).output(1061, 0)
a1.corners(-90.0, as_dots).extended(0.05, 0.05, 0.05, 0.05).output(1062, 0)
a1.select { |p| p.bbox.width < 0.8 }.output(1100, 0)
a1.collect { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1101, 0)
a1.collect_to_region { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1102, 0)
a1.collect_to_edges { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1103, 0)
a1.collect { |p| p.is_box? && p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(120, 120) }.output(1104, 0)
a1.collect { |p| p.is_box? && [ p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(150, 150), p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(120, 120) ] }.output(1105, 0)
lx = polygon_layer
a1.each { |p| p.is_box? && lx.insert(p) }
lx.output(1106, 0)
a1.collect { |p| p.is_box? && RBA::Region::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))).sized(120) }.output(1107, 0)
a1.collect { |p| p.is_box? && RBA::Polygon::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))) }.output(1108, 0)
a1.collect { |p| p.is_box? && RBA::DPolygon::new(p.bbox) }.output(1109, 0)
a1.collect { |p| p.is_box? && RBA::SimplePolygon::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))) }.output(1110, 0)
a1.collect { |p| p.is_box? && RBA::DSimplePolygon::new(p.bbox) }.output(1111, 0)
a1.collect_to_edges { |p| p.is_box? && p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(120, 120) }.output(1112, 0)
a1.collect_to_edges { |p| p.is_box? && [ p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(150, 150), p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(120, 120) ] }.output(1113, 0)
a1.collect_to_edges { |p| p.is_box? && RBA::Region::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))).sized(120) }.output(1114, 0)
a1.collect_to_edges { |p| p.is_box? && RBA::Polygon::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))) }.output(1115, 0)
a1.collect_to_edges { |p| p.is_box? && RBA::DPolygon::new(p.bbox) }.output(1116, 0)
a1.collect_to_edges { |p| p.is_box? && RBA::SimplePolygon::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))) }.output(1117, 0)
a1.collect_to_edges { |p| p.is_box? && RBA::DSimplePolygon::new(p.bbox) }.output(1118, 0)
a1.edges.select { |p| p.length < 0.8 }.output(1120, 0)
a1.edges.collect { |p| p.length < 0.8 && p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1121, 0)
a1.edges.collect_to_region { |p| p.length < 0.8 && p.bbox.enlarged(0.1, 0.1) }.output(1122, 0)
a1.edges.collect_to_region { |p| p.length < 0.8 && p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(100, 100) }.output(1123, 0)
# edge pair collect
a1.width(1.5).collect { |p| p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1120, 0)
a1.width(1.5).collect_to_edge_pairs { |p| p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1121, 0)

19
testdata/drc/drcSimpleTests_3.drc vendored Normal file
View File

@ -0,0 +1,19 @@
# Foreign cell test
source($drc_test_source, "TOPTOP")
target($drc_test_target)
cell("TOP")
a1 = input(1)
b1 = input(2)
output_cell("NEW")
a1.and(b1).output(1000, 0)
cell("TOPTOP")
a1.and(b1).output(1001, 0)

BIN
testdata/drc/drcSimpleTests_au1.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au2.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au3.gds vendored Normal file

Binary file not shown.

494
testdata/drc/drcSuiteTests.drc vendored Normal file
View File

@ -0,0 +1,494 @@
def message(m)
$stdout.puts(m)
$stdout.flush
end
def run_testsuite(dm, ic, tiled = false)
lb = 100
a = input(RBA::LayerInfo::new(1, 0))
b = input(2)
c = input(3)
x = input(10)
y = input(11)
h = {}
layers.each { |l| h[l] = true }
h[RBA::LayerInfo::new(1, 0)] || raise("missing layer 1/0 in layers list")
c.is_merged? == false || raise("unexpected value")
message "--- general #{lb}"
l1 = a&b
l1.output(lb, dm)
l1.is_empty? && raise("must not be empty")
a.and(b).xor(l1).is_empty? || raise("xor not empty")
tiled || (a.and(b).is_merged? == true || raise("unexpected value"))
a.xor(b).output(RBA::LayerInfo::new(lb + 1, dm))
a.xor(b).xor(a ^ b).is_empty? || raise("xor not empty")
a.not(b).output(lb + 2, dm)
a.not(b).xor(a - b).is_empty? || raise("xor not empty")
a.or(b).output(lb + 3, dm)
a.or(b).xor(a | b).is_empty? || raise("xor not empty")
a.join(b).output(lb + 4, dm)
a.join(b).xor(a + b).is_empty? || raise("xor not empty")
if !tiled
a.join(b).data.size == 16 * ic || raise("unexpected shape count")
end
c.raw.is_clean? == false || raise("unexpected value")
# c.raw switched the semantics
c.is_clean? == false || raise("unexpected value")
(c.area / ic).to_s == "10.0" || raise("unexpected value")
(c.edges.length / ic).to_s == "18.0" || raise("unexpected value")
(c.perimeter / ic).to_s == "18.0" || raise("unexpected value")
c.clean
c.is_clean? == true || raise("unexpected value")
(c.area / ic).to_s == "9.0" || raise("unexpected value")
(c.edges.length / ic).to_s == "14.0" || raise("unexpected value")
(c.perimeter / ic).to_s == "14.0" || raise("unexpected value")
(c.dup.area / ic).to_s == "9.0" || raise("unexpected value")
(c.raw.clean.area / ic).to_s == "9.0" || raise("unexpected value")
(c.area / ic).to_s == "9.0" || raise("unexpected value")
(c.raw.area / ic).to_s == "10.0" || raise("unexpected value")
c.clean
if ic == 1
c.bbox.to_s == "(-4,-5;0,-2)" || raise("unexpected value")
end
lb += 10
message "--- centers, start_segments, end_segments #{lb}"
a.edges.centers(0.1).extended_out(0.01).output(lb, dm)
a.edges.centers(0, 0.5).extended_out(0.01).output(lb + 1, dm)
a.edges.centers(0.5, 0.5).extended_out(0.01).output(lb + 2, dm)
a.edges.start_segments(0.1).extended_out(0.01).output(lb + 3, dm)
a.edges.start_segments(0, 0.5).extended_out(0.01).output(lb + 4, dm)
a.edges.start_segments(0.5, 0.5).extended_out(0.01).output(lb + 5, dm)
a.edges.end_segments(0.1).extended_out(0.01).output(lb + 6, dm)
a.edges.end_segments(0, 0.5).extended_out(0.01).output(lb + 7, dm)
a.edges.end_segments(0.5, 0.5).extended_out(0.01).output(lb + 8, dm)
a.polygons? == true || raise("unexpected value")
a.edges? == false || raise("unexpected value")
a.edge_pairs? == false || raise("unexpected value")
a.edges.edge_pairs? == false || raise("unexpected value")
a.edges.polygons? == false || raise("unexpected value")
a.edges.edges? == true || raise("unexpected value")
a.space(0.5).edge_pairs? == true || raise("unexpected value")
a.space(0.5).polygons? == false || raise("unexpected value")
a.space(0.5).edges? == false || raise("unexpected value")
lb += 10
message "--- extended #{lb}"
a.edges.with_length(0.6).extended(begin: 0.1, end: 0.15, out: 0.1, in: -0.05).output(lb, dm)
a.edges.with_length(0.6).extended(out: 0.1, in: -0.05).output(lb + 1, dm)
a.edges.with_length(0..0.7).extended(out: 0.1, in: -0.05).output(lb + 2, dm)
a.edges.with_length(0..0.7).extended(out: 0.1, in: -0.05, joined: true).output(lb + 3, dm)
a.edges.with_length(0..0.7).extended(begin: 0.1, end: 0.15, out: 0.1, in: 0.05, joined: true).output(lb + 4, dm)
a.edges.with_length(0..0.7).extended(0.1, 0.15, 0.1, 0.05).output(lb + 5, dm)
a.edges.with_length(0..0.7).extended(0.1, 0.15, 0.1, 0.05, true).output(lb + 6, dm)
a.edges.with_length(0..0.7).extended_out(0.1).output(lb + 7, dm)
a.edges.with_length(0..0.7).extended_in(0.1).output(lb + 8, dm)
lb += 10
message "--- extents #{lb}"
b.extents.output(lb, dm)
lb += 10
message "--- first_edges, second_edges, edges #{lb}"
a.enclosing(b, 0.5, whole_edges).first_edges.extended_out(0.01).output(lb, dm)
a.enclosing(b, 0.5, whole_edges).second_edges.extended_out(0.01).output(lb + 1, dm)
a.enclosing(b, 0.5, whole_edges).edges.extended_out(0.01).output(lb + 2, dm)
lb += 10
message "--- hulls, holes #{lb}"
c.xor(b).holes.output(lb, dm)
c.xor(b).hulls.output(lb + 1, dm)
c.xor(b).xor(c.xor(b).hulls - c.xor(b).holes).is_empty? || raise("xor not empty")
lb += 10
message "--- interacting, in, not_in #{lb}"
b.interacting(a).output(lb, dm)
b.interacting(a).in(b).output(lb + 1, dm)
(b|a).not_in(b).output(lb + 2, dm)
x.in(b).output(lb + 3, dm)
b.sized(0.1).in(b).is_empty? == true || raise("unexpected value")
lb += 10
message "--- inside, outside, overlapping, interacting #{lb}"
b.inside(c).output(lb, dm)
b.outside(c).output(lb + 1, dm)
b.overlapping(c).output(lb + 2, dm)
b.interacting(c).output(lb + 3, dm)
bdup = b.dup
bdup.select_inside(c)
bdup.xor(b.inside(c)).output(lb + 4, dm)
bdup = b.dup
bdup.select_outside(c)
bdup.xor(b.outside(c)).output(lb + 5, dm)
bdup = b.dup
bdup.select_overlapping(c)
bdup.xor(b.overlapping(c)).output(lb + 6, dm)
bdup = b.dup
bdup.select_interacting(c)
bdup.xor(b.interacting(c)).output(lb + 7, dm)
lb += 10
message "--- merge #{lb}"
c.raw
if !tiled
c.merged.is_merged? == true || raise("unexpected value")
end
c.merged.output(lb, dm)
c.merged(2).output(lb + 1, dm)
c.merged(3).output(lb + 2, dm)
c.clean
cdup = c.dup
cdup.merge.xor(c.merged).output(lb + 3, dm)
cdup.xor(c.merged).output(lb + 4, dm)
cdup = c.dup
cdup.merge(2).xor(c.merged(2)).output(lb + 5, dm)
cdup.xor(c.merged(2)).output(lb + 6, dm)
lb += 10
message "--- move, transform, rotate, scale #{lb}"
c.moved(0.2, -0.1).output(lb, dm)
cdup = c.dup
cdup.move(0.2, -0.1)
cdup.xor(c.moved(0.2, -0.1)).is_empty? == true || raise("xor not empty")
t = RBA::DCplxTrans::new(0.5)
c.transformed(t).output(lb + 1, dm)
cdup = c.dup
cdup.transform(t)
cdup.xor(c.transformed(t)).is_empty? == true || raise("xor not empty")
c.scaled(0.5).output(lb + 2, dm)
cdup = c.dup
cdup.scale(0.5)
cdup.xor(c.scaled(0.5)).is_empty? == true || raise("xor not empty")
c.rotated(45).output(lb + 3, dm)
cdup = c.dup
cdup.rotate(45)
cdup.xor(c.rotated(45)).is_empty? == true || raise("xor not empty")
lb += 10
message "--- rectangles, rectilinear #{lb}"
a.rectangles.output(lb, dm)
a.non_rectangles.output(lb + 1, dm)
a.rectilinear.output(lb + 2, dm)
a.non_rectilinear.output(lb + 3, dm)
c.raw
c.non_rectangles.output(lb + 4, dm)
c.clean
c.rectangles.output(lb + 5, dm)
lb += 10
message "--- enclosing #{lb}"
a.enclosing(b, 0.5).polygons.output(lb, dm)
a.enclosing(b, 0.5).polygons.xor(a.enc(b, 0.5).polygons).is_empty? == true || raise("xor not empty")
a.enclosing(b, 0.5, euclidian).polygons.output(lb + 1, dm)
a.enclosing(b, 0.5, square).polygons.output(lb + 2, dm)
a.enclosing(b, 0.5, projection).polygons.output(lb + 3, dm)
a.enclosing(b, 0.5, euclidian, whole_edges).polygons.output(lb + 4, dm)
a.enclosing(b, 0.5, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
a.enclosing(b, 0.5, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
a.enclosing(b, 0.5, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- enclosing (edges) #{lb}"
ae = a.edges
be = b.edges
ae.enclosing(be, 0.5).polygons.output(lb, dm)
ae.enclosing(be, 0.5).polygons.xor(ae.enc(be, 0.5).polygons).is_empty? == true || raise("xor not empty")
ae.enclosing(be, 0.5, euclidian).polygons.output(lb + 1, dm)
ae.enclosing(be, 0.5, square).polygons.output(lb + 2, dm)
ae.enclosing(be, 0.5, projection).polygons.output(lb + 3, dm)
ae.enclosing(be, 0.5, euclidian, whole_edges).polygons.output(lb + 4, dm)
ae.enclosing(be, 0.5, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
ae.enclosing(be, 0.5, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
ae.enclosing(be, 0.5, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- isolated #{lb}"
b.isolated(0.4).polygons.output(lb, dm)
b.isolated(0.4).polygons.xor(b.iso(0.4).polygons).is_empty? == true || raise("xor not empty")
b.isolated(0.4, euclidian).polygons.output(lb + 1, dm)
b.isolated(0.4, square).polygons.output(lb + 2, dm)
b.isolated(0.4, projection).polygons.output(lb + 3, dm)
b.isolated(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
b.isolated(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
b.isolated(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
b.isolated(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- notch #{lb}"
b.notch(0.4).polygons.output(lb, dm)
b.notch(0.4, euclidian).polygons.output(lb + 1, dm)
b.notch(0.4, square).polygons.output(lb + 2, dm)
b.notch(0.4, projection).polygons.output(lb + 3, dm)
b.notch(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
b.notch(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
b.notch(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
b.notch(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- overlap #{lb}"
a.overlap(b, 0.5).polygons.output(lb, dm)
a.overlap(b, 0.5, euclidian).polygons.output(lb + 1, dm)
a.overlap(b, 0.5, square).polygons.output(lb + 2, dm)
a.overlap(b, 0.5, projection).polygons.output(lb + 3, dm)
a.overlap(b, 0.5, euclidian, whole_edges).polygons.output(lb + 4, dm)
a.overlap(b, 0.5, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
a.overlap(b, 0.5, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
a.overlap(b, 0.5, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- overlap (edges) #{lb}"
ae = a.edges
be = b.edges
ae.overlap(be, 0.5).polygons.output(lb, dm)
ae.overlap(be, 0.5, euclidian).polygons.output(lb + 1, dm)
ae.overlap(be, 0.5, square).polygons.output(lb + 2, dm)
ae.overlap(be, 0.5, projection).polygons.output(lb + 3, dm)
ae.overlap(be, 0.5, euclidian, whole_edges).polygons.output(lb + 4, dm)
ae.overlap(be, 0.5, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
ae.overlap(be, 0.5, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
ae.overlap(be, 0.5, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- separation #{lb}"
a.separation(b, 0.4).polygons.output(lb, dm)
a.separation(b, 0.4).polygons.xor(a.sep(b, 0.4).polygons).is_empty? == true || raise("xor not empty")
a.separation(b, 0.4, euclidian).polygons.output(lb + 1, dm)
a.separation(b, 0.4, square).polygons.output(lb + 2, dm)
a.separation(b, 0.4, projection).polygons.output(lb + 3, dm)
a.separation(b, 0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
a.separation(b, 0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
a.separation(b, 0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
a.separation(b, 0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- sized #{lb}"
x.sized(0.1).output(lb, dm)
x.sized(0.1, 0).output(lb + 1, dm)
x.sized(0.1, diamond_limit).output(lb + 2, dm)
x.sized(0.1, octagon_limit).output(lb + 3, dm)
x.sized(0.1, square_limit).output(lb + 4, dm)
x.sized(0.1, acute_limit).output(lb + 5, dm)
x.sized(0.1, no_limit).output(lb + 6, dm)
xdup = x.dup
xdup.size(0.1, 0)
xdup.xor(x.sized(0.1, 0)).is_empty? == true || raise("xor not empty")
a.sized(4.0, no_limit).output(lb + 7, dm)
lb += 10
message "--- space #{lb}"
b.space(0.4).polygons.output(lb, dm)
b.space(0.4, euclidian).polygons.output(lb + 1, dm)
b.space(0.4, square).polygons.output(lb + 2, dm)
b.space(0.4, projection).polygons.output(lb + 3, dm)
b.space(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
b.space(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
b.space(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
b.space(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- space (edges) #{lb}"
be = b.edges
be.space(0.4).polygons.output(lb, dm)
be.space(0.4, euclidian).polygons.output(lb + 1, dm)
be.space(0.4, square).polygons.output(lb + 2, dm)
be.space(0.4, projection).polygons.output(lb + 3, dm)
be.space(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
be.space(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
be.space(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
be.space(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- width #{lb}"
b.width(0.4).polygons.output(lb, dm)
b.width(0.4, euclidian).polygons.output(lb + 1, dm)
b.width(0.4, square).polygons.output(lb + 2, dm)
b.width(0.4, projection).polygons.output(lb + 3, dm)
b.width(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
b.width(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
b.width(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
b.width(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- width (edges) #{lb}"
be = b.edges
be.width(0.4).polygons.output(lb, dm)
be.width(0.4, euclidian).polygons.output(lb + 1, dm)
be.width(0.4, square).polygons.output(lb + 2, dm)
be.width(0.4, projection).polygons.output(lb + 3, dm)
be.width(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
be.width(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
be.width(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
be.width(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
message "--- with_angle #{lb}"
a.edges.with_angle(90.degree).extended_out(0.01).output(lb, dm)
a.edges.with_angle(45 .. 90.1).extended_out(0.01).output(lb + 1, dm)
a.edges.with_angle(0, 45.1).extended_out(0.01).output(lb + 2, dm)
a.edges.without_angle(90.degree).extended_out(0.01).output(lb + 3, dm)
a.edges.without_angle(45 .. 90.1).extended_out(0.01).output(lb + 4, dm)
a.edges.without_angle(0, 45.1).extended_out(0.01).output(lb + 5, dm)
a.with_angle(135).polygons.output(lb + 6, dm)
lb += 10
message "--- with_area #{lb}"
b.with_area(0.49.um2).output(lb, dm)
b.with_area(0 .. 0.5).output(lb + 1, dm)
b.with_area(0.5, nil).output(lb + 2, dm)
b.without_area(0.49.um2).output(lb + 3, dm)
b.without_area(nil, 0.5).output(lb + 4, dm)
b.without_area(0.5, nil).output(lb + 5, dm)
lb += 10
message "--- with_perimeter #{lb}"
b.with_perimeter(2.8.um).output(lb, dm)
b.with_perimeter(0 .. 3.um).output(lb + 1, dm)
b.with_perimeter(3.um, nil).output(lb + 2, dm)
b.without_perimeter(2.8.um).output(lb + 3, dm)
b.without_perimeter(nil, 3.um).output(lb + 4, dm)
b.without_perimeter(3.um, nil).output(lb + 5, dm)
lb += 10
message "--- with_bbox_height #{lb}"
b.with_bbox_height(0.7.um).output(lb, dm)
b.with_bbox_height(0 .. 0.7.um+1.dbu).output(lb + 1, dm)
b.with_bbox_height(0.7.um, nil).output(lb + 2, dm)
b.without_bbox_height(0.7.um).output(lb + 3, dm)
b.without_bbox_height(nil, 0.7.um+1.dbu).output(lb + 4, dm)
b.without_bbox_height(0.7.um, nil).output(lb + 5, dm)
lb += 10
message "--- with_bbox_width #{lb}"
b.with_bbox_width(0.7.um).output(lb, dm)
b.with_bbox_width(0 .. 0.7.um+1.dbu).output(lb + 1, dm)
b.with_bbox_width(0.7.um, nil).output(lb + 2, dm)
b.without_bbox_width(0.7.um).output(lb + 3, dm)
b.without_bbox_width(nil, 0.7.um+1.dbu).output(lb + 4, dm)
b.without_bbox_width(0.7.um, nil).output(lb + 5, dm)
lb += 10
message "--- with_bbox_min #{lb}"
b.with_bbox_min(0.7.um).output(lb, dm)
b.with_bbox_min(0 .. 0.7.um+1.dbu).output(lb + 1, dm)
b.with_bbox_min(0.7.um, nil).output(lb + 2, dm)
b.without_bbox_min(0.7.um).output(lb + 3, dm)
b.without_bbox_min(nil, 0.7.um+1.dbu).output(lb + 4, dm)
b.without_bbox_min(0.7.um, nil).output(lb + 5, dm)
lb += 10
message "--- with_bbox_max #{lb}"
b.with_bbox_max(0.7.um).output(lb, dm)
b.with_bbox_max(0 .. 0.7.um+1.dbu).output(lb + 1, dm)
b.with_bbox_max(0.7.um, nil).output(lb + 2, dm)
b.without_bbox_max(0.7.um).output(lb + 3, dm)
b.without_bbox_max(nil, 0.7.um+1.dbu).output(lb + 4, dm)
b.without_bbox_max(0.7.um, nil).output(lb + 5, dm)
lb += 10
message "--- with_length #{lb}"
a.edges.with_length(0.6.um).extended_out(0.01).output(lb, dm)
a.edges.with_length(0 .. 0.6.um+1.dbu).extended_out(0.01).output(lb + 1, dm)
a.edges.with_length(0.6, nil).extended_out(0.01).output(lb + 2, dm)
a.edges.without_length(0.6.um).extended_out(0.01).output(lb + 3, dm)
a.edges.without_length(0 .. 0.6.um+1.dbu).extended_out(0.01).output(lb + 4, dm)
a.edges.without_length(0.6, nil).extended_out(0.01).output(lb + 5, dm)
lb += 10
message "--- ongrid, snap #{lb}"
a.ongrid(0.2).polygons(1.dbu).output(lb, dm)
a.ongrid(0, 0.1).polygons(1.dbu).output(lb + 1, dm)
a.snapped(0.2).output(lb + 2, dm)
a.snapped(0, 0.1).output(lb + 3, dm)
adup = a.dup
adup.snap(0.2)
adup.xor(a.snapped(0.2)).output(lb + 4, dm)
lb += 10
message "--- odd polygon check #{lb}"
y.odd_polygons.output(lb, dm)
end
if $drc_test_mode == 1
source($drc_test_source, "TOP")
target($drc_test_target, "TOP")
run_testsuite(0, 1)
elsif $drc_test_mode == 2
target($drc_test_target, "TOPTOP")
source($drc_test_source, "TOPTOP")
run_testsuite(0, 900)
elsif $drc_test_mode == 3
target($drc_test_target, "TOPTOP")
source($drc_test_source, "TOPTOP")
tiles(4.1, 5.2)
# must be that big ...
tile_borders(1.um, 1.um)
threads(4)
run_testsuite(0, 900, true)
elsif $drc_test_mode == 4
target($drc_test_target, "TOPTOP")
source($drc_test_source, "TOPTOP")
tiles(10000.0, 10000.0)
tile_borders(0, 0)
threads(4)
run_testsuite(0, 900, true)
end

BIN
testdata/drc/drcSuiteTests_au1.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSuiteTests_au2.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSuiteTests_au3.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSuiteTests_au4.gds vendored Normal file

Binary file not shown.