From e31d7afb6442ef02a27234907e37606959ebf601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Fri, 5 Feb 2021 23:28:04 +0100 Subject: [PATCH 1/2] Reduce risk of DRC polygon split artefacts in deep mode (#722) * Fixed a segfault with simple 'klayout -v' * is_halfmanhattan polygon predicate, confine polygon splitting to halfmanhattan Splitting any-angle polygons for area reduction in the deep processor creates a risk of introducing grid-snap artefacts. Hence we avoid this. --- src/db/db/dbHierarchyBuilder.cc | 4 ++- src/db/db/dbPolygon.h | 45 ++++++++++++++++++++++++- src/db/db/gsiDeclDbPolygon.cc | 28 +++++++++------- src/db/unit_tests/dbPolygonTests.cc | 46 ++++++++++++++++++++++++++ src/drc/unit_tests/drcSimpleTests.cc | 5 +++ src/lay/lay/layApplication.cc | 2 +- testdata/drc/drcSimpleTests_28.drc | 18 ++++++++++ testdata/drc/drcSimpleTests_28.gds | Bin 0 -> 2154 bytes testdata/drc/drcSimpleTests_au28d.gds | Bin 0 -> 2154 bytes testdata/ruby/dbPolygonTest.rb | 26 +++++++++++++++ testdata/ruby/dbSimplePolygonTest.rb | 22 ++++++++++++ 11 files changed, 181 insertions(+), 15 deletions(-) create mode 100644 testdata/drc/drcSimpleTests_28.drc create mode 100644 testdata/drc/drcSimpleTests_28.gds create mode 100644 testdata/drc/drcSimpleTests_au28d.gds diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 0ae678485..5a6751f87 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -601,7 +601,9 @@ ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db } } - if ((m_max_vertex_count >= 4 && poly.vertices () > m_max_vertex_count) || (m_area_ratio > 2.0 && poly.area_ratio () > m_area_ratio)) { + // NOTE: only halfmanhattan polygons are guaranteed not to generate grid snap artefacts when splitting. + // This is important to maintain the connection integrity of shape clusters. + if (poly.is_halfmanhattan () && ((m_max_vertex_count >= 4 && poly.vertices () > m_max_vertex_count) || (m_area_ratio > 2.0 && poly.area_ratio () > m_area_ratio))) { std::vector split_polygons; db::split_polygon (poly, split_polygons); diff --git a/src/db/db/dbPolygon.h b/src/db/db/dbPolygon.h index 7c5b4aa3c..56e8b5e04 100644 --- a/src/db/db/dbPolygon.h +++ b/src/db/db/dbPolygon.h @@ -743,7 +743,29 @@ public: return true; } - /** + /** + * @brief returns true if the contour is a half-manhattan contour (multiples of 45 degree) + */ + bool is_halfmanhattan () const + { + if (((size_t) mp_points & 1) != 0) { + return true; + } + if (m_size < 2) { + return false; + } + point_type pl = mp_points [m_size - 1]; + for (size_t i = 0; i < m_size; ++i) { + point_type p = mp_points [i]; + if (! coord_traits::equals (p.x (), pl.x ()) && ! coord_traits::equals (p.y (), pl.y ()) && ! coord_traits::equals (std::abs (p.x () - pl.x ()), std::abs (p.y () - pl.y ()))) { + return false; + } + pl = p; + } + return true; + } + + /** * @brief Returns true if the contour is a hole * * Since this method employs the orientation property the results are only valid for @@ -1671,6 +1693,19 @@ public: return true; } + /** + * @brief Returns true, if the polygon is halfmanhattan + */ + bool is_halfmanhattan () const + { + for (size_t i = 0; i < m_ctrs.size (); ++i) { + if (! m_ctrs [i].is_halfmanhattan ()) { + return false; + } + } + return true; + } + /** * @brief Returns the number of points in the polygon */ @@ -2801,6 +2836,14 @@ public: return m_hull.is_rectilinear (); } + /** + * @brief Returns true, if the polygon is halfmanhattan + */ + bool is_halfmanhattan () const + { + return m_hull.is_halfmanhattan (); + } + /** * @brief The number of holes * diff --git a/src/db/db/gsiDeclDbPolygon.cc b/src/db/db/gsiDeclDbPolygon.cc index d0f07fcda..76f3315c9 100644 --- a/src/db/db/gsiDeclDbPolygon.cc +++ b/src/db/db/gsiDeclDbPolygon.cc @@ -75,11 +75,6 @@ struct simple_polygon_defs return c->hull ().size (); } - static bool is_rectilinear (C *c) - { - return c->hull ().is_rectilinear (); - } - static bool is_empty (C *c) { return c->hull ().size () == 0; @@ -349,9 +344,16 @@ struct simple_polygon_defs method_ext ("is_empty?", &is_empty, "@brief Returns a value indicating whether the polygon is empty\n" ) + - method_ext ("is_rectilinear?", &is_rectilinear, + method ("is_rectilinear?", &C::is_rectilinear, "@brief Returns a value indicating whether the polygon is rectilinear\n" ) + + method ("is_halfmanhattan?", &C::is_halfmanhattan, + "@brief Returns a value indicating whether the polygon is half-manhattan\n" + "Half-manhattan polygons have edges which are multiples of 45 degree. These polygons can be clipped at a rectangle without " + "potential grid snapping.\n" + "\n" + "This predicate was introduced in version 0.27.\n" + ) + method_ext ("inside?", &inside, gsi::arg ("p"), "@brief Gets a value indicating whether the given point is inside the polygon\n" "If the given point is inside or on the edge the polygon, true is returned. " @@ -871,11 +873,6 @@ struct polygon_defs return c->vertices (); } - static bool is_rectilinear (C *c) - { - return c->is_rectilinear (); - } - static bool is_empty (C *c) { return c->vertices () == 0; @@ -1151,9 +1148,16 @@ struct polygon_defs method_ext ("is_empty?", &is_empty, "@brief Returns a value indicating whether the polygon is empty\n" ) + - method_ext ("is_rectilinear?", &is_rectilinear, + method ("is_rectilinear?", &C::is_rectilinear, "@brief Returns a value indicating whether the polygon is rectilinear\n" ) + + method ("is_halfmanhattan?", &C::is_halfmanhattan, + "@brief Returns a value indicating whether the polygon is half-manhattan\n" + "Half-manhattan polygons have edges which are multiples of 45 degree. These polygons can be clipped at a rectangle without " + "potential grid snapping.\n" + "\n" + "This predicate was introduced in version 0.27.\n" + ) + method_ext ("hash", &hash_value, "@brief Computes a hash value\n" "Returns a hash value for the given polygon. This method enables polygons as hash keys.\n" diff --git a/src/db/unit_tests/dbPolygonTests.cc b/src/db/unit_tests/dbPolygonTests.cc index fbacfade3..c8729acdf 100644 --- a/src/db/unit_tests/dbPolygonTests.cc +++ b/src/db/unit_tests/dbPolygonTests.cc @@ -83,6 +83,8 @@ TEST(1) EXPECT_EQ (tl::to_string (p.area_ratio ()), "1"); EXPECT_EQ (p.perimeter (), db::Polygon::perimeter_type (2200)); EXPECT_EQ (p.is_box (), true); + EXPECT_EQ (p.is_rectilinear (), true); + EXPECT_EQ (p.is_halfmanhattan (), true); c2.push_back (db::Point (10, 10)); c2.push_back (db::Point (10, 390)); @@ -96,6 +98,9 @@ TEST(1) c3.push_back (db::Point (90, 510)); p.insert_hole (c3.begin (), c3.end ()); EXPECT_EQ (p.holes (), size_t (2)); + EXPECT_EQ (p.is_box (), false); + EXPECT_EQ (p.is_rectilinear (), true); + EXPECT_EQ (p.is_halfmanhattan (), true); EXPECT_EQ (p.to_string (), std::string ("(0,0;0,1000;100,1000;100,0/10,10;90,10;90,390;10,390/10,510;90,510;90,890;10,890)")); db::DPolygon dp (p, db::cast_op ()); @@ -148,6 +153,27 @@ TEST(1) p.clear (); EXPECT_EQ (p, empty); + + c1.clear (); + c1.push_back (db::Point (0, 0)); + c1.push_back (db::Point (0, 1000)); + c1.push_back (db::Point (100, 1100)); + c1.push_back (db::Point (100, 0)); + p.assign_hull (c1.begin (), c1.end ()); + EXPECT_EQ (p.is_box (), false); + EXPECT_EQ (p.is_rectilinear (), false); + EXPECT_EQ (p.is_halfmanhattan (), true); + + + c1.clear (); + c1.push_back (db::Point (0, 0)); + c1.push_back (db::Point (0, 1000)); + c1.push_back (db::Point (100, 1101)); + c1.push_back (db::Point (100, 0)); + p.assign_hull (c1.begin (), c1.end ()); + EXPECT_EQ (p.is_box (), false); + EXPECT_EQ (p.is_rectilinear (), false); + EXPECT_EQ (p.is_halfmanhattan (), false); } @@ -172,6 +198,8 @@ TEST(2) EXPECT_EQ (tl::to_string (p.area_ratio ()), "1"); EXPECT_EQ (p.perimeter (), db::SimplePolygon::perimeter_type (2000+200)); EXPECT_EQ (p.is_box (), true); + EXPECT_EQ (p.is_rectilinear (), true); + EXPECT_EQ (p.is_halfmanhattan (), true); EXPECT_EQ (p.to_string (), "(0,0;0,1000;100,1000;100,0)"); db::DSimplePolygon dp (p, db::cast_op ()); @@ -213,6 +241,24 @@ TEST(2) p.clear (); EXPECT_EQ (p, empty); + + c1.clear (); + c1.push_back (db::Point (0, 0)); + c1.push_back (db::Point (0, 1000)); + c1.push_back (db::Point (100, 1100)); + c1.push_back (db::Point (100, 0)); + p.assign_hull (c1.begin (), c1.end ()); + EXPECT_EQ (p.is_rectilinear (), false); + EXPECT_EQ (p.is_halfmanhattan (), true); + + c1.clear (); + c1.push_back (db::Point (0, 0)); + c1.push_back (db::Point (0, 1000)); + c1.push_back (db::Point (100, 1101)); + c1.push_back (db::Point (100, 0)); + p.assign_hull (c1.begin (), c1.end ()); + EXPECT_EQ (p.is_rectilinear (), false); + EXPECT_EQ (p.is_halfmanhattan (), false); } TEST(3) diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index b52c4213f..9f0d45e6a 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1147,3 +1147,8 @@ TEST(27d_advancedShielding) { run_test (_this, "27", true); } + +TEST(28_inputFragmentation) +{ + run_test (_this, "28", true); +} diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index f52ac9bd3..21bc51c24 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -1474,7 +1474,7 @@ GuiApplication::start_recording () lay::Dispatcher * GuiApplication::dispatcher () const { - return mp_mw->dispatcher (); + return mp_mw ? mp_mw->dispatcher () : 0; } void diff --git a/testdata/drc/drcSimpleTests_28.drc b/testdata/drc/drcSimpleTests_28.drc new file mode 100644 index 000000000..1775c164b --- /dev/null +++ b/testdata/drc/drcSimpleTests_28.drc @@ -0,0 +1,18 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0) +l2 = input(2, 0) +l3 = input(3, 0) + +l1.output(1, 0) +l2.output(2, 0) +l3.output(3, 0) + +l1.width(4.995.um, projection, angle_limit(50)).output(100, 0) + diff --git a/testdata/drc/drcSimpleTests_28.gds b/testdata/drc/drcSimpleTests_28.gds new file mode 100644 index 0000000000000000000000000000000000000000..ec5efa65a439aeaaa6f82d4d87d4e14b5e1ff913 GIT binary patch literal 2154 zcmaKtO-Phc6o%jV#u+V9$1=+re={}nFHO@#%djYl2$YI86&CF@BO)mJ+mzHMg2>uL zh6T~0s0e~UqG%Dhiv*)pL@mTfG9|se={a3Dr^Uc9FV8a{_q^wRh$0B~ARY=5KO;aG znJ7lx-0w&VqT9D_1Tw;r=9Zqd+g{%tZD@T~dF$rhcElt9;iA!FT}Oa~Bp{j+AcSaY z0H7=u1~&8q%kqHLZ9s7&P<;_7c?q-(1Mz$R@`QAQU*8R6T?eYNffbLuN4=7pd^7)Z zNg7b`1t=`_9`#CY@=XyS^8!%*5Gc6qJ?fR*7$!$}`BB=RN9`+~n)af!HC=Y>4wZ>pkj~+~n)Vfz*$jeIKy& zm-nbwa+9we08-k4qE7ap%X`!-xyi4&1SG#@cj|$~?0|aIE4j(n>;mSuvO8>a=05LH zujD3Q&F&{XXLtAv8SlMEy^@=J)i)rqhTXZw9_;WQ^-6B?m5+hQeIRc?d+^G8)GN8k zSDfZz7O;DqecA*)Pw6=as8@26FW&+LH-PLh_TULU+`(8A_ei{wn|#>8kgr zS8|gtZgg&Pbhf*R$=;)0$xXf};@rexc9-{8p&$GG7=a)P8V>3H9#5o@D9`#CY^10*AeP?%K zea=mN@E-L_Zt^(;&W+Zx`<7{;&nzr7!XqE&*YQ6W zr2~~;fTA+*QLp4C-xLP2E&vq|fx_F~qh85PzHxvDI>o~{2^3^|k9s9H`L#X3{Nuoi zO+eli?@_PhCg0EwWDEmkJcHah-lJa0O}@SYh#%t2205>@-lJa0O@8$lkoJ+Y?*$hB z@*ed{Zt`{gKx!LM+`%4ndXIV~H~CeUfRwlFPCc-Y9Z-*YB{%unUBKKHc8875+UGs$ zmE7cO*!|dZc8AZ9`QCffE4j&6e*>bm?9MgzV2AgpS8|iDdJKf`1Nr;egIC_8Udc_q z@-!E-klo|#)5qy~O3yh!y^@=J#TFpA0pyIb2T$nX4#u0fN8**-jd(;VvH&Vy$cW{n7y+^&0n|#h?=Y}7!`}LgT8}CuCCzcvcKHH4DNCj-=$%`e67H>`+F}`&g9d4ls_fo E4~<%0?f?J) literal 0 HcmV?d00001 diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index e573b975c..468864b35 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -34,6 +34,7 @@ class DBPolygon_TestClass < TestBase assert_equal( a.is_box?, false ) assert_equal( a.is_empty?, true ) assert_equal( a.is_rectilinear?, false ) + assert_equal( a.is_halfmanhattan?, false ) b = a.dup a = RBA::DPolygon::new( [ RBA::DPoint::new( 0, 1 ), RBA::DPoint::new( 1, 5 ), RBA::DPoint::new( 5, 5 ) ] ) @@ -44,6 +45,7 @@ class DBPolygon_TestClass < TestBase assert_equal( a.num_points_hull, 3 ) assert_equal( a.is_empty?, false ) assert_equal( a.is_rectilinear?, false ) + assert_equal( a.is_halfmanhattan?, false ) c = a.dup assert_equal( a == b, false ) @@ -55,6 +57,7 @@ class DBPolygon_TestClass < TestBase assert_equal( a.is_box?, true ) assert_equal( a.is_empty?, false ) assert_equal( a.is_rectilinear?, true ) + assert_equal( a.is_halfmanhattan?, true ) assert_equal( a.to_s, "(5,-10;5,15;20,15;20,-10)" ) assert_equal( RBA::Polygon::new(a).to_s, "(5,-10;5,15;20,15;20,-10)" ) assert_equal( a.num_points_hull, 4 ) @@ -148,6 +151,17 @@ class DBPolygon_TestClass < TestBase p = RBA::DPolygon::ellipse( RBA::DBox::new(-10000, -20000, 30000, 40000), 4 ) assert_equal(p.to_s, "(10000,-20000;-10000,10000;10000,40000;30000,10000)") + # halfmanhattan variants + p = RBA::DPolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 100 ) ]) + assert_equal(p.is_halfmanhattan?, true) + assert_equal(p.is_rectilinear?, false) + p = RBA::DPolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 101 ) ]) + assert_equal(p.is_halfmanhattan?, false) + assert_equal(p.is_rectilinear?, false) + p = RBA::DPolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 100 ), RBA::DPoint::new( 100, 0) ]) + assert_equal(p.is_halfmanhattan?, true) + assert_equal(p.is_rectilinear?, true) + end # Polygon basics @@ -300,6 +314,17 @@ class DBPolygon_TestClass < TestBase p = RBA::Polygon::ellipse( RBA::Box::new(-10000, -20000, 30000, 40000), 4 ) assert_equal(p.to_s, "(10000,-20000;-10000,10000;10000,40000;30000,10000)") + # halfmanhattan variants + p = RBA::Polygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 100 ) ]) + assert_equal(p.is_halfmanhattan?, true) + assert_equal(p.is_rectilinear?, false) + p = RBA::Polygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 101 ) ]) + assert_equal(p.is_halfmanhattan?, false) + assert_equal(p.is_rectilinear?, false) + p = RBA::Polygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 100 ), RBA::Point::new( 100, 0) ]) + assert_equal(p.is_halfmanhattan?, true) + assert_equal(p.is_rectilinear?, true) + end # Polygon parametrized edge iterator @@ -367,6 +392,7 @@ class DBPolygon_TestClass < TestBase assert_equal(p.to_s, "()") assert_equal(p.is_empty?, true) assert_equal(p.is_rectilinear?, false) + assert_equal(p.is_halfmanhattan?, false) pts = [ RBA::Point::new(0, 0) ] p = RBA::Polygon::new(pts) diff --git a/testdata/ruby/dbSimplePolygonTest.rb b/testdata/ruby/dbSimplePolygonTest.rb index 4a35ab0ee..850640561 100644 --- a/testdata/ruby/dbSimplePolygonTest.rb +++ b/testdata/ruby/dbSimplePolygonTest.rb @@ -119,6 +119,17 @@ class DBSimplePolygon_TestClass < TestBase p = RBA::DSimplePolygon::ellipse( RBA::DBox::new(-10000, -20000, 30000, 40000), 4 ) assert_equal(p.to_s, "(10000,-20000;-10000,10000;10000,40000;30000,10000)") + # halfmanhattan variants + p = RBA::DSimplePolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 100 ) ]) + assert_equal(p.is_halfmanhattan?, true) + assert_equal(p.is_rectilinear?, false) + p = RBA::DSimplePolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 101 ) ]) + assert_equal(p.is_halfmanhattan?, false) + assert_equal(p.is_rectilinear?, false) + p = RBA::DSimplePolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 100 ), RBA::DPoint::new( 100, 0) ]) + assert_equal(p.is_halfmanhattan?, true) + assert_equal(p.is_rectilinear?, true) + end # SimplePolygon basics @@ -245,6 +256,17 @@ class DBSimplePolygon_TestClass < TestBase p = RBA::SimplePolygon::ellipse( RBA::Box::new(-10000, -20000, 30000, 40000), 4 ) assert_equal(p.to_s, "(10000,-20000;-10000,10000;10000,40000;30000,10000)") + # halfmanhattan variants + p = RBA::SimplePolygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 100 ) ]) + assert_equal(p.is_halfmanhattan?, true) + assert_equal(p.is_rectilinear?, false) + p = RBA::SimplePolygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 101 ) ]) + assert_equal(p.is_halfmanhattan?, false) + assert_equal(p.is_rectilinear?, false) + p = RBA::SimplePolygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 100 ), RBA::Point::new( 100, 0) ]) + assert_equal(p.is_halfmanhattan?, true) + assert_equal(p.is_rectilinear?, true) + end # raw mode polygons From d8c0ea806aaff228b2cdfcd86d498e676edaf397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Fri, 5 Feb 2021 23:28:22 +0100 Subject: [PATCH 2/2] Issue 723 fixed. (#724) * Fixed a segfault with simple 'klayout -v' * Fixed #723 --- src/tl/tl/tlFileUtils.cc | 6 +++- src/tl/unit_tests/tlFileUtilsTests.cc | 41 +++++++++++++++++++++++++++ src/tl/unit_tests/tlStreamTests.cc | 8 +++--- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/tl/tl/tlFileUtils.cc b/src/tl/tl/tlFileUtils.cc index d4028e093..93fa77860 100644 --- a/src/tl/tl/tlFileUtils.cc +++ b/src/tl/tl/tlFileUtils.cc @@ -287,7 +287,11 @@ std::string dirname (const std::string &s) parts.pop_back (); } - return tl::join (parts, ""); + if (parts.empty ()) { + return is_part_with_separator (s) ? "" : "."; + } else { + return tl::join (parts, ""); + } } std::string filename (const std::string &s) diff --git a/src/tl/unit_tests/tlFileUtilsTests.cc b/src/tl/unit_tests/tlFileUtilsTests.cc index edf0ae01f..b77b7968e 100644 --- a/src/tl/unit_tests/tlFileUtilsTests.cc +++ b/src/tl/unit_tests/tlFileUtilsTests.cc @@ -351,6 +351,9 @@ TEST (10) EXPECT_EQ (tl::normalize_path ("d:/"), "D:\\"); EXPECT_EQ (tl::normalize_path ("d://"), "D:\\"); + EXPECT_EQ (tl::dirname ("hello"), "."); + EXPECT_EQ (tl::dirname (".\\hello"), "."); + EXPECT_EQ (tl::dirname ("/hello"), ""); EXPECT_EQ (tl::dirname ("/hello/world"), "\\hello"); EXPECT_EQ (tl::dirname ("\\hello\\world"), "\\hello"); EXPECT_EQ (tl::dirname ("/hello//world/"), "\\hello\\world"); @@ -406,6 +409,33 @@ TEST (10) EXPECT_EQ (tl::combine_path ("hello", "world"), "hello\\world"); EXPECT_EQ (tl::combine_path ("hello", ""), "hello"); EXPECT_EQ (tl::combine_path ("hello", "", true), "hello\\"); + EXPECT_EQ (tl::combine_path ("", "hello", true), "\\hello"); + EXPECT_EQ (tl::combine_path (".", "hello", true), ".\\hello"); + + EXPECT_EQ (tl::combine_path (tl::dirname ("hello"), tl::filename ("hello")), ".\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("\\hello"), tl::filename ("\\hello")), "\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("c:\\hello"), tl::filename ("c:\\hello")), "C:\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("\\c:\\hello"), tl::filename ("\\c:\\hello")), "C:\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("\\\\hello"), tl::filename ("\\\\hello")), "\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("\\\\server:\\hello"), tl::filename ("\\\\server:\\hello")), "\\\\server:\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("\\hello\\x"), tl::filename ("\\hello\\x")), "\\hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("c:\\hello\\x"), tl::filename ("c:\\hello\\x")), "C:\\hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("\\c:\\hello\\x"), tl::filename ("\\c:\\hello\\x")), "C:\\hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("\\\\hello\\x"), tl::filename ("\\\\hello\\x")), "\\\\hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("\\hello\\x\\y"), tl::filename ("\\hello\\x\\y")), "\\hello\\x\\y"); + + EXPECT_EQ (tl::combine_path (tl::dirname ("hello/x"), tl::filename ("hello/x")), "hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("/hello"), tl::filename ("/hello")), "\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("c:/hello"), tl::filename ("c:/hello")), "C:\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("/c:/hello"), tl::filename ("/c:/hello")), "C:\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("//hello"), tl::filename ("//hello")), "\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("//server:/hello"), tl::filename ("//server:/hello")), "\\\\server:\\hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("/hello/x"), tl::filename ("/hello/x")), "\\hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("c:/hello/x"), tl::filename ("c:/hello/x")), "C:\\hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("/c:/hello/x"), tl::filename ("/c:/hello/x")), "C:\\hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("//hello/x"), tl::filename ("//hello/x")), "\\\\hello\\x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("/hello/x/y"), tl::filename ("/hello/x/y")), "\\hello\\x\\y"); + EXPECT_EQ (tl::combine_path (tl::dirname ("hello/x"), tl::filename ("hello/x")), "hello\\x"); tl::file_utils_force_reset (); @@ -436,6 +466,9 @@ TEST (11) EXPECT_EQ (tl::join (tl::split_path ("/"), "+"), "/"); EXPECT_EQ (tl::join (tl::split_path ("//"), "+"), "/"); + EXPECT_EQ (tl::dirname ("hello"), "."); + EXPECT_EQ (tl::dirname ("./hello"), "."); + EXPECT_EQ (tl::dirname ("/hello"), ""); EXPECT_EQ (tl::dirname ("/hello/world"), "/hello"); EXPECT_EQ (tl::dirname ("/hello//world/"), "/hello/world"); EXPECT_EQ (tl::dirname ("hello//world/"), "hello/world"); @@ -461,6 +494,14 @@ TEST (11) EXPECT_EQ (tl::combine_path ("hello", "world"), "hello/world"); EXPECT_EQ (tl::combine_path ("hello", ""), "hello"); EXPECT_EQ (tl::combine_path ("hello", "", true), "hello/"); + EXPECT_EQ (tl::combine_path ("", "hello", true), "/hello"); + EXPECT_EQ (tl::combine_path (".", "hello", true), "./hello"); + + EXPECT_EQ (tl::combine_path (tl::dirname ("hello"), tl::filename ("hello")), "./hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("/hello"), tl::filename ("/hello")), "/hello"); + EXPECT_EQ (tl::combine_path (tl::dirname ("/hello/x"), tl::filename ("/hello/x")), "/hello/x"); + EXPECT_EQ (tl::combine_path (tl::dirname ("/hello/x/y"), tl::filename ("/hello/x/y")), "/hello/x/y"); + EXPECT_EQ (tl::combine_path (tl::dirname ("hello/x"), tl::filename ("hello/x")), "hello/x"); tl::file_utils_force_reset (); diff --git a/src/tl/unit_tests/tlStreamTests.cc b/src/tl/unit_tests/tlStreamTests.cc index a684f14fa..daad877f7 100644 --- a/src/tl/unit_tests/tlStreamTests.cc +++ b/src/tl/unit_tests/tlStreamTests.cc @@ -138,15 +138,15 @@ TEST(TextInputStream) tl::InputStream is (fn); tl::TextInputStream tis (is); EXPECT_EQ (tis.get_line (), "Hello, world!"); - EXPECT_EQ (tis.line_number (), 1); + EXPECT_EQ (tis.line_number (), size_t (1)); EXPECT_EQ (tis.get_line (), "With another line"); - EXPECT_EQ (tis.line_number (), 2); + EXPECT_EQ (tis.line_number (), size_t (2)); EXPECT_EQ (tis.peek_char (), '\n'); EXPECT_EQ (tis.get_line (), ""); - EXPECT_EQ (tis.line_number (), 3); + EXPECT_EQ (tis.line_number (), size_t (3)); EXPECT_EQ (tis.peek_char (), 's'); EXPECT_EQ (tis.get_line (), "separated by a LFCR and CRLF."); - EXPECT_EQ (tis.line_number (), 4); + EXPECT_EQ (tis.line_number (), size_t (4)); EXPECT_EQ (tis.at_end (), true); }