code: def test_cv_backtest(df):
      """Tests `forecast_pipeline` with various combinations of CV and backtest.
  
      Parameters tested:
  
          - test_horizon
          - cv_horizon
          - cv_min_train_periods
          - cv_expanding_window
          - cv_use_most_recent_splits
          - cv_periods_between_splits
          - cv_periods_between_train_test
          - cv_max_splits
      """
      # Both CV and backtest
      with warnings.catch_warnings():
          warnings.simplefilter("ignore")
          test_horizon = 11
          cv_horizon = 10
          result = forecast_pipeline(
              df,
              pipeline=get_dummy_pipeline(),
              forecast_horizon=24,
              test_horizon=test_horizon,
              cv_horizon=cv_horizon,
              cv_expanding_window=True,  # custom values
              cv_use_most_recent_splits=True,
              cv_min_train_periods=30,
              cv_periods_between_splits=180,
              cv_periods_between_train_test=1,
              cv_max_splits=3,
          )
          backtest_params = (
              result.grid_search.best_estimator_.get_params()
          )
          forecast_params = result.model.get_params()
          for params in [backtest_params, forecast_params]:
              assert params["estimator__constant"] is None
              assert params["estimator__quantile"] is None
              assert params["estimator__strategy"] == "mean"
          assert result.backtest.forecast_horizon == test_horizon
          assert result.grid_search.cv_results_ is not None
          expected_cv_params = {
              "forecast_horizon": cv_horizon,
              "expanding_window": True,
              "use_most_recent_splits": True,
              "min_train_periods": 30,
              "periods_between_splits": 180,
              "periods_between_train_test": 1,
              "max_splits": 3,
              "min_splits": 1,
          }
          for param, value in expected_cv_params.items():
              assert getattr(result.grid_search.cv, param) == value
  
      # Only CV (skip backtest)
      with warnings.catch_warnings():
          warnings.simplefilter("ignore")
          test_horizon = 0  # skip backtest
          cv_horizon = 10
          result = forecast_pipeline(
              df,
              pipeline=get_dummy_pipeline(),
              forecast_horizon=24,
              test_horizon=test_horizon,
              cv_horizon=cv_horizon,
              cv_expanding_window=False,
              cv_use_most_recent_splits=False,
              cv_min_train_periods=None,
              cv_periods_between_splits=None,
              cv_periods_between_train_test=100,
              cv_max_splits=10,
          )
          backtest_params = (
              result.grid_search.best_estimator_.get_params()
          )
          forecast_params = result.model.get_params()
          for params in [backtest_params, forecast_params]:
              assert params["estimator__constant"] is None
              assert params["estimator__quantile"] is None
              assert params["estimator__strategy"] == "mean"
          assert result.backtest is None
          assert result.grid_search.cv_results_ is not None
          expected_cv_params = {
              "forecast_horizon": cv_horizon,
              "expanding_window": False,
              "use_most_recent_splits": False,
              "min_train_periods": 20,  # auto-populated by RollingTimeSeriesSplit
              "periods_between_splits": 10,  # auto-populated by RollingTimeSeriesSplit
              "periods_between_train_test": 100,
              "max_splits": 10,
              "min_splits": 1,
          }
          for param, value in expected_cv_params.items():
              assert getattr(result.grid_search.cv, param) == value
  
      # Only backtest (skip CV)
      with warnings.catch_warnings():
          warnings.simplefilter("ignore")
          test_horizon = 11
          cv_horizon = 0  # skip CV
          result = forecast_pipeline(
              df,
              pipeline=get_dummy_pipeline(),
              forecast_horizon=24,
              test_horizon=test_horizon,
              cv_horizon=cv_horizon,
              cv_expanding_window=True,
              cv_use_most_recent_splits=True,
              cv_min_train_periods=30,
              cv_periods_between_splits=180,
              cv_periods_between_train_test=1,
              cv_max_splits=3,
          )
          backtest_params = (
              result.grid_search.best_estimator_.get_params()
          )
          forecast_params = result.model.get_params()
          for params in [backtest_params, forecast_params]:
              assert params["estimator__constant"] is None
              assert params["estimator__quantile"] is None
              assert params["estimator__strategy"] == "mean"
          assert result.backtest.forecast_horizon == test_horizon
          # dummy RandomizedSearchCV object has only the applicable attributes
          assert result.grid_search.cv is None
          assert not hasattr(result.grid_search, "cv_results_")
          assert not hasattr(result.grid_search, "best_index_")
          assert not hasattr(result.grid_search, "scorer_")
          assert not hasattr(result.grid_search, "refit_time_")
          assert result.grid_search.best_params_ == {}
          assert result.grid_search.n_splits_ == 0
  
          cv_max_splits = 0  # skips CV using cv_max_splits
          result = forecast_pipeline(
              df,
              pipeline=get_dummy_pipeline(),
              forecast_horizon=24,
              test_horizon=test_horizon,
              cv_horizon=3,
              cv_expanding_window=True,
              cv_use_most_recent_splits=True,
              cv_min_train_periods=30,
              cv_periods_between_splits=180,
              cv_periods_between_train_test=1,
              cv_max_splits=cv_max_splits,
          )
          assert result.grid_search.cv is None
          assert result.grid_search.n_splits_ == 0
  
imports: import datetime
  import math
  import sys
  import warnings
  import numpy
  import pandas
  import pytest
  from scipy.stats import randint
  from sklearn.metrics import explained_variance_score
  from sklearn.metrics import mean_absolute_error
  from sklearn.metrics import mean_squared_error
  from sklearn.pipeline import Pipeline
  from greykite.common.constants import ACTUAL_COL
  from greykite.common.constants import ADJUSTMENT_DELTA_COL
  from greykite.common.constants import END_TIME_COL
  from greykite.common.constants import FRACTION_OUTSIDE_TOLERANCE
  from greykite.common.constants import METRIC_COL
  from greykite.common.constants import PREDICTED_COL
  from greykite.common.constants import QUANTILE_SUMMARY_COL
  from greykite.common.constants import START_TIME_COL
  from greykite.common.constants import TIME_COL
  from greykite.common.constants import VALUE_COL
  from greykite.common.constants import R2_null_model_score
  from greykite.common.evaluation import EvaluationMetricEnum
  from greykite.common.evaluation import add_finite_filter_to_scorer
  from greykite.common.evaluation import add_preaggregation_to_scorer
  from greykite.common.python_utils import assert_equal
  from greykite.common.python_utils import unique_elements_in_list
  from greykite.common.testing_utils import generate_df_for_tests
  from greykite.common.testing_utils import generate_df_with_reg_for_tests
  from greykite.framework.constants import CV_REPORT_METRICS_ALL
  from greykite.framework.constants import FRACTION_OUTSIDE_TOLERANCE_NAME
  from greykite.framework.input.univariate_time_series import UnivariateTimeSeries
  from greykite.framework.pipeline.pipeline import forecast_pipeline
  from greykite.framework.templates.prophet_template import ProphetTemplate
  from greykite.framework.utils.framework_testing_utils import check_forecast_pipeline_result
  from greykite.framework.utils.framework_testing_utils import mock_pipeline
  from greykite.sklearn.estimator.null_model import DummyEstimator
  from greykite.sklearn.estimator.prophet_estimator import ProphetEstimator
  from greykite.sklearn.estimator.silverkite_estimator import SilverkiteEstimator
  from greykite.sklearn.estimator.simple_silverkite_estimator import SimpleSilverkiteEstimator
  from greykite.sklearn.transform.column_selector import ColumnSelector
  from greykite.sklearn.transform.drop_degenerate_transformer import DropDegenerateTransformer
  from greykite.sklearn.transform.dtype_column_selector import DtypeColumnSelector
  from greykite.sklearn.transform.normalize_transformer import NormalizeTransformer
  from greykite.sklearn.transform.null_transformer import NullTransformer
  from greykite.sklearn.transform.pandas_feature_union import PandasFeatureUnion
  from greykite.sklearn.transform.zscore_outlier_transformer import ZscoreOutlierTransformer
label_desc: Use image node_id 10 for calling a global function with example usage: test_cv_backtest(df) without return types