# Generated by CodiumAI
import unittest
from unittest.mock import Mock
from bencher.example.benchmark_data import SimpleBenchClass, SimpleBenchClassFloat
import bencher as bch


class TestBenchRunner(unittest.TestCase):
    # Tests that bch.BenchRunner can be created with default configuration and the import statement in the bch.BenchRunner class is fixed
    def test_benchrunner_default_configuration_fixed(self):
        bench_runner = bch.BenchRunner("bench_runner_test")
        self.assertEqual(bench_runner.run_cfg.use_sample_cache, True)
        self.assertEqual(bench_runner.run_cfg.only_hash_tag, True)
        self.assertEqual(bench_runner.run_cfg.level, 2)
        self.assertEqual(bench_runner.publisher, None)
        self.assertEqual(bench_runner.bench_fns, [])

    # Tests that Benchable functions can be added to bch.BenchRunner instance
    def test_benchrunner_add_benchable_functions(self):
        bench_runner = bch.BenchRunner("bench_runner_test")
        bench_fn1 = Mock()
        bench_fn2 = Mock()
        bench_runner.add_run(bench_fn1)
        bench_runner.add_run(bench_fn2)
        self.assertEqual(len(bench_runner.bench_fns), 2)
        self.assertIn(bench_fn1, bench_runner.bench_fns)
        self.assertIn(bench_fn2, bench_runner.bench_fns)

    def test_benchrunner_handle_empty_list(self):
        bench_runner = bch.BenchRunner("bench_runner_test")
        results = bench_runner.run()
        self.assertEqual(len(results), 0)

    def test_benchrunner_benchable_class(self):
        bench_runner = bch.BenchRunner("bench_runner_test")
        bench_runner.add_bench(SimpleBenchClass())
        results = bench_runner.run(run_cfg=bch.BenchRunCfg(run_tag="1"))

        self.assertEqual(results[0].bench_cfg.run_tag, "1")

    def test_benchrunner_cache(self):
        from datetime import datetime

        run_tag = str(datetime.now())

        bench_runner = bch.BenchRunner(
            "bench_runner_test_cache", run_cfg=bch.BenchRunCfg(run_tag=run_tag)
        )

        bench_class = SimpleBenchClass()
        # bench = bch.Bench("test_bench", bench_class, run_cfg=run_cfg, report=report            )

        def run_bench_class(run_cfg: bch.BenchRunCfg, report: bch.BenchReport) -> bch.BenchCfg:
            bench = bch.Bench("test_bench1_cache", bench_class, run_cfg=run_cfg, report=report)
            bench.plot_sweep("bench_1")
            return bench

        bench_runner.add_run(run_bench_class)

        # run with unique tag and with cache, should not hit cache because unique tag
        results = bench_runner.run()
        self.assertEqual(results[0].sample_cache.worker_wrapper_call_count, 2)
        self.assertEqual(results[0].sample_cache.worker_fn_call_count, 2)
        self.assertEqual(results[0].sample_cache.worker_cache_call_count, 0)
        self.assertEqual(results[0].run_cfg.run_tag, run_tag)

        # run again with the same tag, should hit cache because it was already run
        results = bench_runner.run()
        self.assertEqual(results[0].sample_cache.worker_wrapper_call_count, 2)
        self.assertEqual(results[0].sample_cache.worker_fn_call_count, 2)
        self.assertEqual(results[0].sample_cache.worker_cache_call_count, 0)
        self.assertEqual(results[0].run_cfg.run_tag, run_tag)

        # run with the same tag but set use cache to false, should not hit cache because even tho the tag is the same, use_cache=false
        results = bench_runner.run(use_cache=False)
        self.assertEqual(results[0].sample_cache.worker_wrapper_call_count, 2)
        self.assertEqual(results[0].sample_cache.worker_fn_call_count, 2)
        self.assertEqual(results[0].sample_cache.worker_cache_call_count, 0)
        self.assertEqual(results[0].run_cfg.run_tag, run_tag)

    def test_benchrunner_benchable_class_run_constructor(self):
        bench_runner = bch.BenchRunner("bench_runner_test", run_cfg=bch.BenchRunCfg(run_tag="1"))
        bench_runner.add_bench(SimpleBenchClass())
        results = bench_runner.run()
        self.assertEqual(results[0].bench_cfg.run_tag, "1")

    # def test_benchrunner_level_1(self):
    #     results = bch.BenchRunner("bench_runner_test", AllSweepVars()).run(min_level=1)
    #     self.assertEqual(results[0].result_samples(), 1)

    # def test_benchrunner_level_1_only(self):
    #     results = bch.BenchRunner("bench_runner_test", AllSweepVars()).run(level=1)
    #     self.assertEqual(results[0].result_samples(), 1)

    def test_benchrunner_repeats(self):
        res = bch.Bench(
            "float", SimpleBenchClassFloat(), run_cfg=bch.BenchRunCfg(level=2, repeats=1)
        ).plot_sweep("float")
        self.assertEqual(res.result_samples(), 2)

        res = bch.Bench(
            "float", SimpleBenchClassFloat(), run_cfg=bch.BenchRunCfg(level=2, repeats=5)
        ).plot_sweep("float")
        self.assertEqual(res.result_samples(), 10)

    # def test_benchrunner_cache(self):
    #     res = bch.Bench(
    #         "float", SimpleBenchClassFloat(), run_cfg=bch.BenchRunCfg(level=2, repeats=1)
    #     ).plot_sweep("float")

    #     res = bch.Bench(
    #         "float", SimpleBenchClassFloat(), run_cfg=bch.BenchRunCfg(level=2, repeats=5)
    #     ).plot_sweep("float")
    #     self.assertEqual(res.result_samples(), 10)

    # # Tests that bch.BenchRunner can run Benchable functions with default configuration (fixed)
    # def test_benchrunner_run_default_configuration_fixed(self):

    #     bench_runner = bch.BenchRunner()
    #     bench_fn1 = Mock()
    #     bench_fn2 = Mock()
    #     bench_runner.add_run(bench_fn1)
    #     bench_runner.add_run(bench_fn2)
    #     results = bench_runner.run()

    #     self.assertEqual(len(results), 10)
    #     self.assertEqual(results[0].level, 1)
    #     self.assertEqual(results[1].level, 1)
    #     self.assertEqual(results[2].level, 2)
    #     self.assertEqual(results[3].level, 2)
    #     self.assertEqual(results[4].level, 3)
    #     self.assertEqual(results[5].level, 3)
    #     self.assertEqual(results[6].level, 4)
    #     self.assertEqual(results[7].level, 4)
    #     self.assertEqual(results[8].level, 5)
    #     self.assertEqual(results[9].level, 5)

    # Tests that bch.BenchRunner can run Benchable functions with custom configuration, after fixing the import statements
    # def test_benchrunner_run_custom_configuration_fixed_fixed_import_statements(self):

    #     bench_runner = bch.BenchRunner()
    #     bench_fn1 = Mock()
    #     bench_fn2 = Mock()
    #     bench_runner.add_run(bench_fn1)
    #     bench_runner.add_run(bench_fn2)
    #     run_cfg = bch.BenchRunCfg()
    #     run_cfg.use_sample_cache = False
    #     run_cfg.only_hash_tag = False
    #     run_cfg.level = 3
    #     results = bench_runner.run(run_cfg=run_cfg)
    #     self.assertEqual(len(results), 2)
    #     self.assertEqual(results[0].level, 3)
    #     self.assertEqual(results[1].level, 3)

    # Tests that bch.BenchRunner can publish results of Benchable functions (fixed)
    # def test_benchrunner_publish_results_fixed(self):
    #     class MockBenchable:
    #         def bench(self, run_cfg: bch.BenchRunCfg) -> bch.BenchCfg:
    #             return bch.BenchCfg()

    #     bench_runner = bch.BenchRunner(publisher=Mock())
    #     bench_fn1 = MockBenchable()
    #     bench_fn2 = MockBenchable()
    #     bench_runner.add_run(bench_fn1)
    #     bench_runner.add_run(bench_fn2)
    #     results = bench_runner.run(publish=True)
    #     self.assertEqual(len(results), 10)
    #     self.assertEqual(bench_runner.publisher.call_count, 10)
    #     self.assertEqual(bench_runner.publisher.call_args_list[0][0][0], results[0])
    #     self.assertEqual(bench_runner.publisher.call_args_list[1][0][0], results[1])
    #     self.assertEqual(bench_runner.publisher.call_args_list[2][0][0], results[2])
    #     self.assertEqual(bench_runner.publisher.call_args_list[3][0][0], results[3])
    #     self.assertEqual(bench_runner.publisher.call_args_list[4][0][0], results[4])
    #     self.assertEqual(bench_runner.publisher.call_args_list[5][0][0], results[5])
    #     self.assertEqual(bench_runner.publisher.call_args_list[6][0][0], results[6])
    #     self.assertEqual(bench_runner.publisher.call_args_list[7][0][0], results[7])
    #     self.assertEqual(bench_runner.publisher.call_args_list[8][0][0], results[8])
    #     self.assertEqual(bench_runner.publisher.call_args_list[9][0][0], results[9])

    # Tests that bch.BenchRunner can handle empty list of Benchable functions

    # Tests that bch.BenchRunner can handle empty list of Benchable functions
    # def test_benchrunner_handle_empty_list(self):

    #     def benchable(run_cfg:bch.BenchRunCfg)->bch.BenchCfg:
    #         bench = bch.Bench("sbc",SimpleBenchClass(),run_cfg=run_cfg)
    #         return bench.plot_sweep("sweep1")

    #     bench_runner = bch.BenchRunner()
    #     bench_runner.add_run(benchable)

    #     results = bench_runner.run(run_cfg=bch.BenchRunCfg(run_tag="1"))

    #     self.assertEqual(results[0].bench_cfg.run_tag, "1")

    # Tests that bch.BenchRunner can handle empty list of Benchable functions
