text: """Unit tests for ProductManifold."""
  
  import geomstats.backend as gs
  import geomstats.tests
  from geomstats.geometry.euclidean import Euclidean
  from geomstats.geometry.minkowski import Minkowski
  from geomstats.geometry.product_manifold import (
      NFoldManifold,
      NFoldMetric,
      ProductManifold,
  )
  from geomstats.geometry.product_riemannian_metric import ProductRiemannianMetric
  from tests.conftest import Parametrizer
  from tests.data.product_manifold_data import (
      NFoldManifoldTestData,
      NFoldMetricTestData,
      ProductManifoldTestData,
      ProductRiemannianMetricTestData,
  )
  from tests.geometry_test_cases import ManifoldTestCase, RiemannianMetricTestCase
  
  
  class TestProductManifold(ManifoldTestCase, metaclass=Parametrizer):
      space = ProductManifold
      skip_test_random_tangent_vec_is_tangent = True
      skip_test_projection_belongs = True
  
      testing_data = ProductManifoldTestData()
  
      def test_dimension(self, manifolds, default_point_type, expected):
          space = self.space(manifolds, default_point_type=default_point_type)
          self.assertAllClose(space.dim, expected)
  
      def test_regularize(self, manifolds, default_point_type, point):
          space = self.space(manifolds, default_point_type=default_point_type)
          result = space.regularize(point)
          self.assertAllClose(result, point)
  
  
  class TestProductRiemannianMetric(RiemannianMetricTestCase, metaclass=Parametrizer):
      metric = connection = ProductRiemannianMetric
      skip_test_parallel_transport_ivp_is_isometry = True
      skip_test_parallel_transport_bvp_is_isometry = True
      skip_test_exp_geodesic_ivp = True
  
      testing_data = ProductRiemannianMetricTestData()
  
      @geomstats.tests.np_autograd_and_torch_only
      def test_inner_product_matrix(
          self, manifolds, default_point_type, point, base_point
      ):
          metric = self.metric(manifolds, default_point_type=default_point_type)
          logs = metric.log(point, base_point)
          result = metric.inner_product(logs, logs)
          expected = metric.squared_dist(base_point, point)
          self.assertAllClose(result, expected)
  
      @geomstats.tests.np_autograd_and_torch_only
      def test_inner_product_matrix_vector(self, default_point_type):
          euclidean = Euclidean(3)
          minkowski = Minkowski(3)
          space = ProductManifold(manifolds=[euclidean, minkowski])
          point = space.random_point(1)
          expected = gs.eye(6)
          expected[3, 3] = -1
          result = space.metric.metric_matrix(point)
          self.assertAllClose(result, expected)
  
      @geomstats.tests.np_and_autograd_only
      def test_dist_exp_after_log_norm(
          self, manifolds, default_point_type, n_samples, einsum_str, expected
      ):
          space = ProductManifold(
              manifolds=manifolds, default_point_type=default_point_type
          )
          point = space.random_point(n_samples)
          base_point = space.random_point(n_samples)
  
          logs = space.metric.log(point, base_point)
          normalized_logs = gs.einsum(
              einsum_str,
              1.0 / space.metric.norm(logs, base_point),
              logs,
          )
          point = space.metric.exp(normalized_logs, base_point)
          result = space.metric.dist(point, base_point)
          self.assertAllClose(result, expected)
  
  
  class TestNFoldManifold(ManifoldTestCase, metaclass=Parametrizer):
      space = NFoldManifold
      skip_test_random_tangent_vec_is_tangent = True
  
      testing_data = NFoldManifoldTestData()
  
      def test_belongs(self, base, power, point, expected):
          space = self.space(base, power)
          self.assertAllClose(space.belongs(point), expected)
  
      def test_shape(self, base, power, expected):
          space = self.space(base, power)
          self.assertAllClose(space.shape, expected)
  
  
  class TestNFoldMetric(RiemannianMetricTestCase, metaclass=Parametrizer):
      metric = connection = NFoldMetric
      skip_test_parallel_transport_ivp_is_isometry = True
      skip_test_parallel_transport_bvp_is_isometry = True
      skip_test_exp_geodesic_ivp = True
      skip_test_geodesic_bvp_belongs = True
      skip_test_geodesic_ivp_belongs = True
      skip_test_log_is_tangent = True
  
      testing_data = NFoldMetricTestData()
  
      def test_inner_product_shape(self, space, n_samples, point, tangent_vec):
          result = space.metric.inner_product(tangent_vec, tangent_vec, point)
          expected = gs.zeros(n_samples)
          self.assertAllClose(result, expected)
  
          point = point[0]
          result = space.metric.inner_product(tangent_vec, tangent_vec, point)
          expected = gs.zeros(n_samples)
          self.assertAllClose(result, expected)
  
          result = space.metric.inner_product(tangent_vec[0], tangent_vec, point)
          self.assertAllClose(result, expected)
  
          expected = 0.0
          result = space.metric.inner_product(tangent_vec[0], tangent_vec[0], point)
          self.assertAllClose(result, expected)
  