From 9e474a73a0463fa3e5e132cdd5c75b976c60ece7 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 16 Dec 2024 15:10:50 +0800 Subject: [PATCH 1/7] update fuzztest --- CMakeLists.txt | 1 + cmake/manifoldDeps.cmake | 2 +- test/polygon_fuzz.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fdbe9c44..7b147bdf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,7 @@ if(MANIFOLD_FUZZ) set(FUZZTEST_FUZZING_MODE ON) # address sanitizer required add_compile_options(-fsanitize=address) + add_link_options(-fsanitize=address) endif() if(TRACY_ENABLE) diff --git a/cmake/manifoldDeps.cmake b/cmake/manifoldDeps.cmake index c4ace570a..8c1b7aa2f 100644 --- a/cmake/manifoldDeps.cmake +++ b/cmake/manifoldDeps.cmake @@ -224,7 +224,7 @@ if(MANIFOLD_FUZZ) FetchContent_Declare( fuzztest GIT_REPOSITORY https://github.com/google/fuzztest.git - GIT_TAG 2606e04a43e5a7730e437a849604a61f1cb0ff28 + GIT_TAG 7b107216fa6cd62659234366aee493d6f8832d46 GIT_PROGRESS TRUE ) FetchContent_MakeAvailable(fuzztest) diff --git a/test/polygon_fuzz.cpp b/test/polygon_fuzz.cpp index c7faaff6a..d7a15db73 100644 --- a/test/polygon_fuzz.cpp +++ b/test/polygon_fuzz.cpp @@ -43,7 +43,7 @@ void TriangulationNoCrash( try { manifold::Triangulate(polys, precision); faulted.store(false); - } catch (manifold::geometryErr e) { + } catch (geometryErr e) { // geometryErr is fine faulted.store(false); } catch (...) { From a66fe2d72d535fc8a0954d7cf6fa285366ea7e3b Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 16 Dec 2024 15:18:58 +0800 Subject: [PATCH 2/7] fix build --- test/polygon_fuzz.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/polygon_fuzz.cpp b/test/polygon_fuzz.cpp index d7a15db73..11ad8da66 100644 --- a/test/polygon_fuzz.cpp +++ b/test/polygon_fuzz.cpp @@ -19,6 +19,7 @@ #include "fuzztest/fuzztest.h" #include "gtest/gtest.h" #include "manifold/polygon.h" +#include "manifold/optional_assert.h" using namespace fuzztest; From b66990c9318302330bdd8f72810db96988a7c722 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 16 Dec 2024 15:48:08 +0800 Subject: [PATCH 3/7] add manifold fuzz --- test/CMakeLists.txt | 5 +++ test/manifold_fuzz.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++ test/polygon_fuzz.cpp | 2 +- 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 test/manifold_fuzz.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 53d571265..daca69d92 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -69,4 +69,9 @@ if(MANIFOLD_FUZZ) target_link_libraries(polygon_fuzz PUBLIC manifold) link_fuzztest(polygon_fuzz) gtest_discover_tests(polygon_fuzz) + + add_executable(manifold_fuzz manifold_fuzz.cpp) + target_link_libraries(manifold_fuzz PUBLIC manifold) + link_fuzztest(manifold_fuzz) + gtest_discover_tests(manifold_fuzz) endif() diff --git a/test/manifold_fuzz.cpp b/test/manifold_fuzz.cpp new file mode 100644 index 000000000..ff3ed2469 --- /dev/null +++ b/test/manifold_fuzz.cpp @@ -0,0 +1,98 @@ +// Copyright 2024 The Manifold Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "fuzztest/fuzztest.h" +#include "gtest/gtest.h" +#include "manifold/manifold.h" + +using namespace fuzztest; + +enum class Transform { Translate, Rotate, Scale }; + +// larger numbers may cause precision issues, prefer to test them later +auto GoodNumbers = OneOf(InRange(0.1, 10.0), InRange(-10.0, -0.1)); +auto Vec3Domain = ArrayOf<3>(GoodNumbers); +auto TransformDomain = PairOf( + ElementOf({Transform::Translate, Transform::Rotate, Transform::Scale}), + Vec3Domain); +auto CsgDomain = VectorOf(PairOf(VectorOf(TransformDomain).WithMaxSize(20), + ElementOf({0, 1}))) + .WithMaxSize(100); + +void SimpleSpheres( + const std::vector>>, int>> + &inputs) { + manifold::ManifoldParams().intermediateChecks = true; + manifold::ManifoldParams().processOverlaps = false; + manifold::Manifold result; + for (const auto &input : inputs) { + auto sphere = manifold::Manifold::Sphere(1); + for (const auto &transform : input.first) { + switch (transform.first) { + case Transform::Translate: + sphere = sphere.Translate({std::get<0>(transform.second), + std::get<1>(transform.second), + std::get<2>(transform.second)}); + break; + case Transform::Rotate: + sphere = sphere.Rotate(std::get<0>(transform.second), + std::get<1>(transform.second), + std::get<2>(transform.second)); + break; + case Transform::Scale: + sphere = sphere.Scale({std::get<0>(transform.second), + std::get<1>(transform.second), + std::get<2>(transform.second)}); + break; + } + } + + std::atomic tid; + std::atomic faulted(true); + auto asyncFuture = std::async( + std::launch::async, [&result, &faulted, &tid, &sphere, &input]() { + tid.store(gettid()); + if (input.second) { + result += sphere; + } else { + result -= sphere; + } + EXPECT_EQ(result.Status(), manifold::Manifold::Error::NoError); + faulted.store(false); + }); + if (asyncFuture.wait_for(std::chrono::milliseconds(10000)) == + std::future_status::timeout) { + printf("timeout after %dms...\n", 10000); + pthread_cancel(tid.load()); + } + + EXPECT_FALSE(faulted.load()); + if (faulted.load()) break; + } +} + +FUZZ_TEST(ManifoldFuzz, SimpleSpheres).WithDomains(CsgDomain); + +TEST(ManifoldFuzz, SimpleSpheresRegression) { + SimpleSpheres( + {{{}, 1}, + {{{Transform::Rotate, + {0.12968745822201236, -0.10000000000000001, 0.10000275736461019}}}, + 1}, + {{}, 0}}); +} diff --git a/test/polygon_fuzz.cpp b/test/polygon_fuzz.cpp index 11ad8da66..785f91144 100644 --- a/test/polygon_fuzz.cpp +++ b/test/polygon_fuzz.cpp @@ -18,8 +18,8 @@ #include "fuzztest/fuzztest.h" #include "gtest/gtest.h" -#include "manifold/polygon.h" #include "manifold/optional_assert.h" +#include "manifold/polygon.h" using namespace fuzztest; From dc45b001ab05f97fb488fc52efef3fd9683ba0f1 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 16 Dec 2024 15:52:04 +0800 Subject: [PATCH 4/7] use cube instead --- test/manifold_fuzz.cpp | 45 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/test/manifold_fuzz.cpp b/test/manifold_fuzz.cpp index ff3ed2469..70a5f2543 100644 --- a/test/manifold_fuzz.cpp +++ b/test/manifold_fuzz.cpp @@ -33,7 +33,7 @@ auto CsgDomain = VectorOf(PairOf(VectorOf(TransformDomain).WithMaxSize(20), ElementOf({0, 1}))) .WithMaxSize(100); -void SimpleSpheres( +void SimpleCube( const std::vector>>, int>> &inputs) { @@ -41,23 +41,23 @@ void SimpleSpheres( manifold::ManifoldParams().processOverlaps = false; manifold::Manifold result; for (const auto &input : inputs) { - auto sphere = manifold::Manifold::Sphere(1); + auto cube = manifold::Manifold::Cube(); for (const auto &transform : input.first) { switch (transform.first) { case Transform::Translate: - sphere = sphere.Translate({std::get<0>(transform.second), - std::get<1>(transform.second), - std::get<2>(transform.second)}); + cube = cube.Translate({std::get<0>(transform.second), + std::get<1>(transform.second), + std::get<2>(transform.second)}); break; case Transform::Rotate: - sphere = sphere.Rotate(std::get<0>(transform.second), - std::get<1>(transform.second), - std::get<2>(transform.second)); + cube = cube.Rotate(std::get<0>(transform.second), + std::get<1>(transform.second), + std::get<2>(transform.second)); break; case Transform::Scale: - sphere = sphere.Scale({std::get<0>(transform.second), - std::get<1>(transform.second), - std::get<2>(transform.second)}); + cube = cube.Scale({std::get<0>(transform.second), + std::get<1>(transform.second), + std::get<2>(transform.second)}); break; } } @@ -65,12 +65,12 @@ void SimpleSpheres( std::atomic tid; std::atomic faulted(true); auto asyncFuture = std::async( - std::launch::async, [&result, &faulted, &tid, &sphere, &input]() { + std::launch::async, [&result, &faulted, &tid, &cube, &input]() { tid.store(gettid()); if (input.second) { - result += sphere; + result += cube; } else { - result -= sphere; + result -= cube; } EXPECT_EQ(result.Status(), manifold::Manifold::Error::NoError); faulted.store(false); @@ -86,13 +86,14 @@ void SimpleSpheres( } } -FUZZ_TEST(ManifoldFuzz, SimpleSpheres).WithDomains(CsgDomain); +FUZZ_TEST(ManifoldFuzz, SimpleCube).WithDomains(CsgDomain); -TEST(ManifoldFuzz, SimpleSpheresRegression) { - SimpleSpheres( - {{{}, 1}, - {{{Transform::Rotate, - {0.12968745822201236, -0.10000000000000001, 0.10000275736461019}}}, - 1}, - {{}, 0}}); +TEST(ManifoldFuzz, SimpleCubeRegression) { + SimpleCube({{{{static_cast(1), + {-0.10000000000000001, 0.10000000000000001, -1.}}}, + 1}, + {{}, 1}, + {{{static_cast(1), + {-0.10000000000000001, -0.10000000000066571, -1.}}}, + 0}}); } From 0359666609d8525ed703829e6e05a80fd2923067 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Tue, 17 Dec 2024 18:08:05 +0800 Subject: [PATCH 5/7] fix comment --- test/manifold_fuzz.cpp | 61 +++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/test/manifold_fuzz.cpp b/test/manifold_fuzz.cpp index 70a5f2543..bf74403f0 100644 --- a/test/manifold_fuzz.cpp +++ b/test/manifold_fuzz.cpp @@ -21,43 +21,50 @@ using namespace fuzztest; -enum class Transform { Translate, Rotate, Scale }; +enum class TransformType { Translate, Rotate, Scale }; +struct Transform { + TransformType ty; + std::array vector; +}; +struct CubeOp { + std::vector transforms; + bool isUnion; +}; // larger numbers may cause precision issues, prefer to test them later auto GoodNumbers = OneOf(InRange(0.1, 10.0), InRange(-10.0, -0.1)); auto Vec3Domain = ArrayOf<3>(GoodNumbers); -auto TransformDomain = PairOf( - ElementOf({Transform::Translate, Transform::Rotate, Transform::Scale}), +auto TransformDomain = StructOf( + ElementOf({TransformType::Translate, TransformType::Rotate, + TransformType::Scale}), Vec3Domain); -auto CsgDomain = VectorOf(PairOf(VectorOf(TransformDomain).WithMaxSize(20), - ElementOf({0, 1}))) - .WithMaxSize(100); +auto CsgDomain = + VectorOf(StructOf(VectorOf(TransformDomain).WithMaxSize(20), + ElementOf({false, true}))) + .WithMaxSize(100); -void SimpleCube( - const std::vector>>, int>> - &inputs) { +void SimpleCube(const std::vector &inputs) { manifold::ManifoldParams().intermediateChecks = true; manifold::ManifoldParams().processOverlaps = false; manifold::Manifold result; for (const auto &input : inputs) { auto cube = manifold::Manifold::Cube(); - for (const auto &transform : input.first) { - switch (transform.first) { - case Transform::Translate: - cube = cube.Translate({std::get<0>(transform.second), - std::get<1>(transform.second), - std::get<2>(transform.second)}); + for (const auto &transform : input.transforms) { + switch (transform.ty) { + case TransformType::Translate: + cube = cube.Translate({std::get<0>(transform.vector), + std::get<1>(transform.vector), + std::get<2>(transform.vector)}); break; - case Transform::Rotate: - cube = cube.Rotate(std::get<0>(transform.second), - std::get<1>(transform.second), - std::get<2>(transform.second)); + case TransformType::Rotate: + cube = cube.Rotate(std::get<0>(transform.vector), + std::get<1>(transform.vector), + std::get<2>(transform.vector)); break; - case Transform::Scale: - cube = cube.Scale({std::get<0>(transform.second), - std::get<1>(transform.second), - std::get<2>(transform.second)}); + case TransformType::Scale: + cube = cube.Scale({std::get<0>(transform.vector), + std::get<1>(transform.vector), + std::get<2>(transform.vector)}); break; } } @@ -67,7 +74,7 @@ void SimpleCube( auto asyncFuture = std::async( std::launch::async, [&result, &faulted, &tid, &cube, &input]() { tid.store(gettid()); - if (input.second) { + if (input.isUnion) { result += cube; } else { result -= cube; @@ -89,11 +96,11 @@ void SimpleCube( FUZZ_TEST(ManifoldFuzz, SimpleCube).WithDomains(CsgDomain); TEST(ManifoldFuzz, SimpleCubeRegression) { - SimpleCube({{{{static_cast(1), + SimpleCube({{{{static_cast(1), {-0.10000000000000001, 0.10000000000000001, -1.}}}, 1}, {{}, 1}, - {{{static_cast(1), + {{{static_cast(1), {-0.10000000000000001, -0.10000000000066571, -1.}}}, 0}}); } From fec7d9b03dcb039312130359d85a337e01bf376c Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 18 Dec 2024 10:27:54 +0800 Subject: [PATCH 6/7] moved regression test out --- test/boolean_test.cpp | 12 ++++++++++++ test/manifold_fuzz.cpp | 23 ++++++++--------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/test/boolean_test.cpp b/test/boolean_test.cpp index e4141375c..478b5758c 100644 --- a/test/boolean_test.cpp +++ b/test/boolean_test.cpp @@ -421,3 +421,15 @@ TEST(Boolean, Precision2) { cube2 = cube2.Translate(vec3(scale * kPrecision)); EXPECT_FALSE((cube ^ cube2).IsEmpty()); } + +TEST(Boolean, SimpleCubeRegression) { + ManifoldParams().intermediateChecks = true; + ManifoldParams().processOverlaps = false; + Manifold result = + Manifold::Cube().Rotate(-0.10000000000000001, 0.10000000000000001, -1.) + + Manifold::Cube() - + Manifold::Cube().Rotate(-0.10000000000000001, -0.10000000000066571, -1.); + EXPECT_EQ(result.Status(), Manifold::Error::NoError); + ManifoldParams().intermediateChecks = false; + ManifoldParams().processOverlaps = true; +} diff --git a/test/manifold_fuzz.cpp b/test/manifold_fuzz.cpp index bf74403f0..95028296c 100644 --- a/test/manifold_fuzz.cpp +++ b/test/manifold_fuzz.cpp @@ -20,6 +20,7 @@ #include "manifold/manifold.h" using namespace fuzztest; +using namespace manifold; enum class TransformType { Translate, Rotate, Scale }; struct Transform { @@ -44,12 +45,13 @@ auto CsgDomain = .WithMaxSize(100); void SimpleCube(const std::vector &inputs) { - manifold::ManifoldParams().intermediateChecks = true; - manifold::ManifoldParams().processOverlaps = false; - manifold::Manifold result; + ManifoldParams().intermediateChecks = true; + ManifoldParams().processOverlaps = false; + Manifold result; for (const auto &input : inputs) { - auto cube = manifold::Manifold::Cube(); + auto cube = Manifold::Cube(); for (const auto &transform : input.transforms) { + printf("transform: %d\n", static_cast(transform.ty)); switch (transform.ty) { case TransformType::Translate: cube = cube.Translate({std::get<0>(transform.vector), @@ -69,6 +71,7 @@ void SimpleCube(const std::vector &inputs) { } } + printf("isUnion: %d\n", input.isUnion); std::atomic tid; std::atomic faulted(true); auto asyncFuture = std::async( @@ -79,7 +82,7 @@ void SimpleCube(const std::vector &inputs) { } else { result -= cube; } - EXPECT_EQ(result.Status(), manifold::Manifold::Error::NoError); + EXPECT_EQ(result.Status(), Manifold::Error::NoError); faulted.store(false); }); if (asyncFuture.wait_for(std::chrono::milliseconds(10000)) == @@ -94,13 +97,3 @@ void SimpleCube(const std::vector &inputs) { } FUZZ_TEST(ManifoldFuzz, SimpleCube).WithDomains(CsgDomain); - -TEST(ManifoldFuzz, SimpleCubeRegression) { - SimpleCube({{{{static_cast(1), - {-0.10000000000000001, 0.10000000000000001, -1.}}}, - 1}, - {{}, 1}, - {{{static_cast(1), - {-0.10000000000000001, -0.10000000000066571, -1.}}}, - 0}}); -} From ea188db7e5d125fda6b299da3f7554b5898e5a1d Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 18 Dec 2024 11:34:27 +0800 Subject: [PATCH 7/7] disable test --- test/boolean_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/boolean_test.cpp b/test/boolean_test.cpp index 478b5758c..40bb00dd3 100644 --- a/test/boolean_test.cpp +++ b/test/boolean_test.cpp @@ -422,7 +422,7 @@ TEST(Boolean, Precision2) { EXPECT_FALSE((cube ^ cube2).IsEmpty()); } -TEST(Boolean, SimpleCubeRegression) { +TEST(Boolean, DISABLED_SimpleCubeRegression) { ManifoldParams().intermediateChecks = true; ManifoldParams().processOverlaps = false; Manifold result =