diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7340d091065e0a1de1cf7510914f0021827c6a93..c3ef11475a0abf37254b5eef60130fe3dfbb4097 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,6 +4,23 @@ stages:
  - Deploy
 
 
+testsuite-clang18:
+  image: i10git.cs.fau.de:5005/walberla/buildenvs/clang-18:latest
+  tags:
+    - docker
+  stage: "Test"
+  needs: []
+  variables:
+    CXX: clang++
+    CC: clang
+  before_script:
+    - cd user_manual/examples
+    - cmake -G Ninja -S . -B build
+    - cd build
+    - cmake --build . --target SfgTests
+  script:
+    - ctest
+
 build-examples:
   image: i10git.cs.fau.de:5005/walberla/buildenvs/clang-18:latest
   tags:
@@ -14,7 +31,7 @@ build-examples:
     CXX: clang++
     CC: clang
   script:
-    - cd user_manual/examples
+    - cd tests
     - cmake -G Ninja -S . -B build
     - cd build
     - cmake --build . --target Examples
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index f6e52227b3c49260f6329d25dfa096a9e3e3dac1..72acde9c5dc7ca88b51038b3798c79810a812883 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -3,6 +3,7 @@ project( sfg-walberla-testsuite )
 
 set(WALBERLA_BUILD_TESTS OFF CACHE BOOL "")
 set(WALBERLA_BUILD_BENCHMARKS OFF CACHE BOOL "")
+set(WALBERLA_BUILD_SHOWCASES OFF CACHE BOOL "")
 set(WALBERLA_BUILD_TUTORIALS OFF CACHE BOOL "")
 
 include(FetchContent)
@@ -20,4 +21,6 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/.. ${CMAKE_BINARY_DIR}/sfg-walberla)
 #   Test Directories
 include(CTest)
 
+add_custom_target( SfgTests )
+
 add_subdirectory( FreeSlip )
diff --git a/tests/CMakePresets.json b/tests/CMakePresets.json
index 11b6c5797a4a848db2ef82c3e601e403848fb15a..48449c2d856200adfa38b7019aa2bcff44144615 100644
--- a/tests/CMakePresets.json
+++ b/tests/CMakePresets.json
@@ -11,6 +11,7 @@
             "binaryDir": "${sourceDir}/build/${presetName}",
             "generator": "Ninja",
             "cacheVariables": {
+                "CMAKE_BUILD_TYPE": "Debug",
                 "WALBERLA_BUILD_TESTS": false
             }
         }
diff --git a/tests/FreeSlip/CMakeLists.txt b/tests/FreeSlip/CMakeLists.txt
index 661ef3c7d06ef4512b754d2aa2614cc313f12430..e47cae2e1bef502e62a8b64dd2dea7f9fa396151 100644
--- a/tests/FreeSlip/CMakeLists.txt
+++ b/tests/FreeSlip/CMakeLists.txt
@@ -2,3 +2,5 @@ add_executable( TestIrregularFreeSlip TestIrregularFreeSlip.cpp )
 walberla_generate_sources( TestIrregularFreeSlip SCRIPTS IrregularFreeSlip.py )
 target_link_libraries( TestIrregularFreeSlip core blockforest field geometry sfg_walberla )
 add_test( NAME TestIrregularFreeSlip COMMAND TestIrregularFreeSlip )
+
+add_dependencies( SfgTests TestIrregularFreeSlip )
diff --git a/tests/FreeSlip/IrregularFreeSlip.py b/tests/FreeSlip/IrregularFreeSlip.py
index 4a5b5cdcccb7fbc580b69827a8aa315f5b604dfe..3fa69cf2042e054618db15ec1779945b9198214a 100644
--- a/tests/FreeSlip/IrregularFreeSlip.py
+++ b/tests/FreeSlip/IrregularFreeSlip.py
@@ -1,22 +1,54 @@
+import sympy as sp
 from pystencilssfg import SourceFileGenerator
-from sfg_walberla.boundaries import FreeSlip
-from lbmpy import LBStencil, Stencil, LBMConfig, create_lb_method
+
 from pystencils import fields, Field
+from lbmpy import LBStencil, Stencil, LBMConfig, LBMOptimisation, create_lb_update_rule
+from lbmpy.macroscopic_value_kernels import macroscopic_values_setter
+
+
+from sfg_walberla import Sweep
+from sfg_walberla.boundaries import FreeSlip
 
 with SourceFileGenerator() as sfg:
-    sfg.namespace("gen")
+    sfg.namespace("TestIrregularFreeSlip::gen")
 
     stencil = LBStencil(Stencil.D3Q19)
     d, q = stencil.D, stencil.Q
     f: Field
-    f = fields(f"f({q}): double[{d}D]", layout="fzyx")  # type: ignore
+    f_tmp: Field
+    f, f_tmp, rho, u = fields(
+        f"f({q}), f_tmp({q}), rho, u({d}): double[{d}D]", layout="fzyx"
+    )  # type: ignore
 
     stencil_name = stencil.name
     sfg.include(f"stencil/{stencil_name}.h")
     sfg.code(f"using LbStencil = walberla::stencil::{stencil_name};")
 
-    lbm_config = LBMConfig(stencil=stencil)
-    lb_method = create_lb_method(lbm_config)
+    lbm_config = LBMConfig(
+        stencil=stencil,
+        output={"density": rho, "velocity": u},
+    )
+    lbm_opt = LBMOptimisation(
+        symbolic_field=f,
+        symbolic_temporary_field=f_tmp,
+    )
+
+    lb_update = create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt)
+    assert lb_update is not None
+
+    lb_update_sweep = Sweep("LbStreamCollide", lb_update)
+    lb_update_sweep.swap_fields(f, f_tmp)
+    sfg.generate(lb_update_sweep)
+
+    lb_init = macroscopic_values_setter(
+        lb_update.method,
+        density=sp.Symbol("density"),
+        velocity=u.center_vector,
+        pdfs=f,
+    )
+    lb_init_sweep = Sweep("LbInit", lb_init)
+    sfg.generate(lb_init_sweep)
+
+    irreg_freeslip = FreeSlip("FreeSlipIrregular", lb_update.method, f, wall_normal=FreeSlip.IRREGULAR)
+    sfg.generate(irreg_freeslip)
 
-    bc = FreeSlip("FreeSlip", lb_method, f, wall_normal=FreeSlip.IRREGULAR)
-    sfg.generate(bc)
diff --git a/tests/FreeSlip/TestIrregularFreeSlip.cpp b/tests/FreeSlip/TestIrregularFreeSlip.cpp
index 68e4ae927e91caafa7693f0a30a2b2ed40f5ef64..c08df34308cc4e8c64d02717cfe1c091c0ecb5a4 100644
--- a/tests/FreeSlip/TestIrregularFreeSlip.cpp
+++ b/tests/FreeSlip/TestIrregularFreeSlip.cpp
@@ -1,9 +1,15 @@
 
 #include "core/all.h"
 #include "blockforest/all.h"
+
 #include "field/all.h"
+#include "field/communication/PackInfo.h"
+#include "field/communication/StencilRestrictedPackInfo.h"
+
 #include "geometry/all.h"
 
+#include "vtk/all.h"
+
 #include <array>
 
 #include "gen/IrregularFreeSlip.hpp"
@@ -13,66 +19,129 @@ namespace TestIrregularFreeSlip
     using namespace walberla;
 
     using PdfField_T = field::GhostLayerField<real_t, gen::LbStencil::Q>;
+    using ScalarField_T = field::GhostLayerField<real_t, 1>;
+    using VectorField_T = field::GhostLayerField<real_t, gen::LbStencil::D>;
     using FlagField_T = FlagField<uint8_t>;
-
-    void run(int argc, char **argv)
+    using CommScheme = blockforest::communication::UniformBufferedScheme<gen::LbStencil>;
+    using PdfsPackInfo = field::communication::StencilRestrictedPackInfo<PdfField_T, gen::LbStencil>;
+
+    /**
+     * Pipe flow with circular cross-section and free-slip walls.
+     * The pipe flow is initialized with a constant velocity in x-direction.
+     * As free-slip walls do not impose any friction, velocity should remain constant in time.
+     */
+    void freeSlipPipe(Environment &env)
     {
-        Environment env{argc, argv};
-
-        AABB domainAabb{0., 0., 0., 1., 1., 1.};
         std::array<uint_t, 3> blocks{1, 1, 1};
-        std::array<uint_t, 3> cpb{32, 32, 32};
+        std::array<uint_t, 3> cpb{4, 32, 32};
+        std::array<bool, 3> periodic{true, false, false};
 
         auto sbfs = blockforest::createUniformBlockGrid(
-            domainAabb,
             blocks[0], blocks[1], blocks[2],
-            cpb[0], cpb[1], cpb[2]);
+            cpb[0], cpb[1], cpb[2],
+            1.0,
+            true,
+            periodic[0], periodic[1], periodic[2]
+        );
 
         BlockDataID pdfsId = field::addToStorage<PdfField_T>(sbfs, "f", real_c(0.0));
+        BlockDataID rhoId = field::addToStorage<ScalarField_T>(sbfs, "rho", real_c(0.0));
+        BlockDataID uId = field::addToStorage<VectorField_T>(sbfs, "u", real_c(0.0));
 
         const BlockDataID flagFieldId = field::addFlagFieldToStorage<FlagField_T>(sbfs, "flagField");
         const FlagUID fluidFlagUid{"Fluid"};
         const FlagUID freeSlipFlagUID{"FreeSlip"};
 
         const CellInterval allCells{{0, 0, 0}, {sbfs->getNumberOfXCellsPerBlock() - 1, sbfs->getNumberOfYCellsPerBlock() - 1, sbfs->getNumberOfZCellsPerBlock() - 1}};
-        const Vector3<real_t> sphereCenter{16., 16., 16.};
-        const real_t sphereRadius{8.};
+        const CellInterval allCellsWithGl{{-1, 0, 0}, {sbfs->getNumberOfXCellsPerBlock(), sbfs->getNumberOfYCellsPerBlock() - 1, sbfs->getNumberOfZCellsPerBlock() - 1}};
+
+        const real_t pipeRadius{14.0};
+        const Vector3<real_t> pipeAnchor{0.0, 16.0, 16.0};
+        const real_t maxVelocity{0.02};
 
         for (auto &block : *sbfs)
         {
             FlagField_T &flagField = *block.getData<FlagField_T>(flagFieldId);
             const uint8_t freeSlipFlag{flagField.getOrRegisterFlag(freeSlipFlagUID)};
 
-            PdfField_T &pdfField = *block.getData<PdfField_T>(pdfsId);
+            VectorField_T &velField = *block.getData<VectorField_T>(uId);
 
-            for (Cell c : allCells)
+            for (Cell c : allCellsWithGl)
             {
                 Cell globalCell{c};
                 sbfs->transformBlockLocalToGlobalCell(globalCell, block);
                 Vector3<real_t> cellCenter{sbfs->getCellCenter(globalCell)};
+                cellCenter[0] = 0.0;
 
-                if ((cellCenter - sphereCenter).sqrLength() < sphereRadius * sphereRadius)
+                Vector3<real_t> initVelocity;
+                real_t radialDistance = (cellCenter - pipeAnchor).length();
+                if (radialDistance > pipeRadius)
                 {
                     flagField.addFlag(c, freeSlipFlag);
-                    for (uint_t q = 0; q < 19; ++q)
-                    {
-                        pdfField.get(c, q) = NAN;
-                    }
+                    initVelocity = Vector3<real_t>{NAN};
+                }
+                else
+                {
+                    initVelocity = Vector3<real_t>{maxVelocity, 0., 0.};
                 }
+
+                velField.get(c, 0) = initVelocity[0];
+                velField.get(c, 1) = initVelocity[1];
+                velField.get(c, 2) = initVelocity[2];
             }
         }
 
         geometry::setNonBoundaryCellsToDomain<FlagField_T>(*sbfs, flagFieldId, fluidFlagUid);
 
-        gen::FreeSlip freeSlip{gen::FreeSlipFactory(sbfs, pdfsId).fromFlagField<FlagField_T>(flagFieldId, freeSlipFlagUID, fluidFlagUid)};
+        auto flagsOutput = field::createVTKOutput<FlagField_T>(flagFieldId, *sbfs, "flags");
+        flagsOutput();
+
+        gen::LbInit initialize { pdfsId, uId, 1.0 };
 
-        for(auto& block: *sbfs){
-            freeSlip( &block );
+        for(auto& b : *sbfs){
+            initialize(&b);
         }
+
+        gen::FreeSlipIrregular freeSlip{
+            gen::FreeSlipIrregularFactory(sbfs, pdfsId).fromFlagField<FlagField_T>(flagFieldId, freeSlipFlagUID, fluidFlagUid)
+        };
+
+        gen::LbStreamCollide streamCollide { pdfsId, rhoId, uId, 1.0 };
+
+        CommScheme comm{sbfs};
+        auto pdfsPackInfo = std::make_shared<PdfsPackInfo>(pdfsId);
+        comm.addPackInfo(pdfsPackInfo);
+
+        auto velOutput = field::createVTKOutput<VectorField_T>(uId, *sbfs, "vel");
+
+        for(uint_t i = 0; i < 10; ++i){
+            comm();
+            for (auto &block : *sbfs)
+            {
+                velOutput();
+                freeSlip(&block);
+                streamCollide(&block);
+
+                VectorField_T & velField = *block.getData< VectorField_T >(uId);
+                FlagField_T & flagField = *block.getData< FlagField_T >(flagFieldId);
+                uint8_t fluidFlag = flagField.getFlag(fluidFlagUid);
+                
+                for(Cell c : allCells){
+                    if( flagField.isFlagSet(c, fluidFlag) ){
+                        WALBERLA_CHECK_FLOAT_EQUAL( velField.get(c, 0), maxVelocity );
+                        WALBERLA_CHECK_FLOAT_EQUAL( velField.get(c, 1), 0. );
+                        WALBERLA_CHECK_FLOAT_EQUAL( velField.get(c, 2), 0. );
+                    }
+                }
+            }
+        }
+
+        velOutput();
     }
 }
 
 int main(int argc, char **argv)
 {
-    TestIrregularFreeSlip::run(argc, argv);
+    walberla::Environment env{argc, argv};
+    TestIrregularFreeSlip::freeSlipPipe(env);
 }
diff --git a/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py b/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
index 1d6678f3121c38964a0d8b6c314f0cb77c16bcf5..a40d6b4c1349ef03a585c8a734d81e286dbbb3df 100644
--- a/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
+++ b/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
@@ -7,7 +7,7 @@ from lbmpy.macroscopic_value_kernels import macroscopic_values_setter
 
 
 from sfg_walberla import Sweep
-from sfg_walberla.boundaries import FreeSlip, IRREGULAR
+from sfg_walberla.boundaries import FreeSlip
 
 with SourceFileGenerator() as sfg:
     sfg.namespace("FreeSlipBubble::gen")
@@ -45,6 +45,5 @@ with SourceFileGenerator() as sfg:
     lb_init_sweep = Sweep("LbInit", lb_init)
     sfg.generate(lb_init_sweep)
 
-    freeslip = FreeSlip("FreeSlip", lb_update.method, f, wall_normal=IRREGULAR)
+    freeslip = FreeSlip("FreeSlip", lb_update.method, f, wall_normal=FreeSlip.IRREGULAR)
     sfg.generate(freeslip)
-