import pytest
from unittest.mock import Mock

from .conftest import EXEMPLAR_GENERATORS


@pytest.mark.parametrize("g", EXEMPLAR_GENERATORS)
def test_can_register_clones_which_are_automatically_reset(g):
    """
    Test that we can register clones on generators, and these are automatically reset when the parent is reset.
    """
    dummy_clone_1 = Mock()
    dummy_clone_2 = Mock()
    g.register_clone(dummy_clone_1)
    g.register_clone(dummy_clone_2)

    g.reset(seed=12345)
    dummy_clone_1.reset.assert_called_once_with(12345)
    dummy_clone_2.reset.assert_called_once_with(12345)

    g.reset(seed=99999)
    dummy_clone_1.reset.assert_called_with(99999)
    dummy_clone_2.reset.assert_called_with(99999)


@pytest.mark.parametrize("g", EXEMPLAR_GENERATORS)
def test_clone_generators(g):
    """
    Test that g.clone() clones a generator and the resulting clone is reset when the parent is reset, producing the same elements
    """
    num_items = 10
    g.reset(seed=12345)

    # Let g generate a few items
    items_g_1 = list(g.generate(num_items))

    # Spawn g and let both generate a few more items
    h = g.clone()
    items_g_2 = list(g.generate(num_items))
    items_h_2 = list(h.generate(num_items))

    # Reset g and re-generate the full list of items for both generators
    g.reset(seed=12345)
    items_g = list(g.generate(2*num_items))
    items_h = list(h.generate(2*num_items))

    # Verify that the items generated by h after spawning
    # as well as the full sets of items are identical.
    assert items_h_2 == items_g_2
    assert items_h == items_g == items_g_1 + items_g_2

import pytest
from unittest.mock import Mock

from .conftest import EXEMPLAR_GENERATORS, EXEMPLAR_PRIMITIVE_GENERATORS


@pytest.mark.parametrize("g", EXEMPLAR_GENERATORS)
def test_can_register_clones_which_are_automatically_reset(g):
    """
    Test that we can register clones on generators, and these are automatically reset when the parent is reset.
    """
    dummy_clone_1 = Mock()
    dummy_clone_2 = Mock()
    g.register_clone(dummy_clone_1)
    g.register_clone(dummy_clone_2)

    g.reset(seed=12345)
    dummy_clone_1.reset.assert_called_once_with(12345)
    dummy_clone_2.reset.assert_called_once_with(12345)

    g.reset(seed=99999)
    dummy_clone_1.reset.assert_called_with(99999)
    dummy_clone_2.reset.assert_called_with(99999)


@pytest.mark.parametrize("g", EXEMPLAR_PRIMITIVE_GENERATORS)
def test_clone_generators(g):
    """
    Test that g.clone() clones a generator and the resulting clone is reset when the parent is reset, producing the same elements
    """
    num_items = 10
    g.reset(seed=12345)

    # Let g generate a few items
    items_g_1 = list(g.generate(num_items))

    # Spawn g and let both generate a few more items
    h = g.clone()
    items_g_2 = list(g.generate(num_items))
    items_h_2 = list(h.generate(num_items))

    # Reset g and re-generate the full list of items for both generators
    g.reset(seed=12345)
    items_g = list(g.generate(2*num_items))
    items_h = list(h.generate(2*num_items))

    # Verify that the items generated by h after spawning
    # as well as the full sets of items are identical.
    assert items_h_2 == items_g_2
    assert items_h == items_g == items_g_1 + items_g_2

Test for cloning does not work for exemplar derived generators because we can't explicitly reset their input generators, so the result is not reproducible in the test