mage'] == get_image_full(REPO_NAME, IMAGE_NAME, IMAGE_TAG)

import pytest
from unittest.mock import Mock, patch

from fairing.train import Trainer, Train
from fairing.backend import NativeBackend
from fairing.strategies.basic import BasicTrainingStrategy
from fairing.builders.container_image_builder import ContainerImageBuilder
from fairing.metaparticle import MetaparticleClient
from fairing.utils import get_image_full

REPO_NAME = 'testrepo'
IMAGE_NAME = 'fairing-test'
IMAGE_TAG = 'test'

@pytest.fixture
def trainer():
    return Trainer(repository=REPO_NAME, image_name=IMAGE_NAME, image_tag=IMAGE_TAG)

@pytest.fixture
def mock_strategy():
    return Mock(spec=BasicTrainingStrategy)

@pytest.fixture
def mock_mp_client():
    return Mock(spec=MetaparticleClient)

@pytest.fixture
def mock_trainer():
    return Mock(spec=Trainer)

@pytest.fixture
def mock_builder():
    return Mock(spec=ContainerImageBuilder)

def test_compile_ast(trainer):
    trainer.fill_image_name_and_tag()
    svc, env = trainer.compile_ast()
    assert env == None
    assert len(svc['jobs']) == 1

    job = svc['jobs'][0]

    assert len(job['containers']) == 1
    assert job['containers'][0]['i

def test_start_training(mock_strategy):
    # Start training should call exec_user_code method from the chosen strategy
    # with the user code as parameter

    # this object will stand in as user code
    fake_user_object = {'fake_prop': 'fake'}

    trainer = Trainer(repository=REPO_NAME,
                      image_name=IMAGE_NAME,
                      image_tag=IMAGE_TAG,
                      strategy=mock_strategy)

    trainer.start_training(fake_user_object)

    mock_strategy.exec_user_code.assert_called_with(fake_user_object)

def test_deploy_training(mock_builder, mock_mp_client, monkeypatch):
    monkeypatch.setattr(
        'fairing.train.MetaparticleClient', mock_mp_client)
    monkeypatch.setattr(
        'fairing.train.get_container_builder', lambda x: mock_builder)

    trainer = Trainer(repository=REPO_NAME)
    trainer.deploy_training(stream_logs=False)

    # Deploy should first generate a Dockerfile, build and finally push the image
    mock_builder.execute.assert_called_once()

@pytest.mark.parametrize("is_runtime_phase", [True, False])
def test_train(is_runtime_phase, mock_trainer, monkeypatch):
    monkeypatch.setattr('fairing.train.Trainer', mock_trainer)
    monkeypatch.setattr('fairing.train.is_runtime_phase',
                        lambda: is_runtime_phase)

    mock_inst = mock_trainer()

    @Train(repository=REPO_NAME)
    class TestModel(object):
        def train(self):
            pass

    model = TestModel()
    model.train()

    # When running outside the metaparticle container (so on a user system),
    # when train() is called, it should build the container and deploy the code into
    # a metaparticle container.
    # Once running in a metaparticle container, train() should instead route to
    # the actual user code (through start_training)
    if is_runtime_phase:
        mock_inst.start_training.assert_called_once()
    else:
        mock_inst.deploy_training.assert_called_once()


if is_runtime_phase:
        mock_inst.start_training.assert_called_once()
    else:
        mock_inst.deploy_training.assert_called_once()

import pytest
from unittest.mock import Mock, patch

from fairing.train import Trainer, Train
from fairing.backend import NativeBackend
from fairing.strategies.basic import BasicTrainingStrategy
from fairing.builders.container_image_builder import ContainerImageBuilder
from fairing.metaparticle import MetaparticleClient
from fairing.utils import get_image_full

REPO_NAME = 'testrepo'
IMAGE_NAME = 'fairing-test'
IMAGE_TAG = 'test'

@pytest.fixture
def trainer():
    return Trainer(repository=REPO_NAME, image_name=IMAGE_NAME, image_tag=IMAGE_TAG)

@pytest.fixture
def mock_strategy():
    return Mock(spec=BasicTrainingStrategy)

@pytest.fixture
def mock_mp_client():
    return Mock(spec=MetaparticleClient)

@pytest.fixture
def mock_trainer():
    return Mock(spec=Trainer)

@pytest.fixture
def mock_builder():
    return Mock(spec=ContainerImageBuilder)

def test_compile_ast(trainer):
    trainer.fill_image_name_and_tag()
    svc, env = trainer.compile_ast()
    assert env == None
    assert len(svc['jobs']) == 1

    job = svc['jobs'][0]

    assert len(job['containers']) == 1
    assert job['containers'][0]['image'] == get_image_full(REPO_NAME, IMAGE_NAME, IMAGE_TAG)

def test_start_training(mock_strategy):
    # Start training should call exec_user_code method from the chosen strategy
    # with the user code as parameter

    # this object will stand in as user code
    fake_user_object = {'fake_prop': 'fake'}

    trainer = Trainer(repository=REPO_NAME,
                      image_name=IMAGE_NAME,
                      image_tag=IMAGE_TAG,
                      strategy=mock_strategy)

    trainer.start_training(fake_user_object)

    mock_strategy.exec_user_code.assert_called_with(fake_user_object)

def test_deploy_training(mock_builder, mock_mp_client, monkeypatch):
    monkeypatch.setattr(
        'fairing.train.MetaparticleClient', mock_mp_client)
    monkeypatch.setattr(
        'fairing.train.get_container_builder', lambda x: mock_builder)

    trainer = Trainer(repository=REPO_NAME)
    trainer.deploy_training(stream_logs=False)

    # Deploy should first generate a Dockerfile, build and finally push the image
    mock_builder.execute.assert_called_once()

@pytest.mark.parametrize("is_runtime_phase", [True, False])
def test_train(is_runtime_phase, mock_trainer, monkeypatch):
    monkeypatch.setattr('fairing.train.Trainer', mock_trainer)
    monkeypatch.setattr('fairing.train.is_runtime_phase',
                        lambda: is_runtime_phase)

    mock_inst = mock_trainer()

    @Train(repository=REPO_NAME)
    class TestModel(object):
        def train(self):
            pass

    model = TestModel()
    model.train()

    # When running outside the metaparticle container (so on a user system),
    # when train() is called, it should build the container and deploy the code into
    # a metaparticle container.
    # Once running in a metaparticle container, train() should instead route to
    # the actual user code (through start_training)


import pytest
from unittest.mock import Mock, patch

from fairing.train import Trainer, Train
from fairing.backend import NativeBackend
from fairing.strategies.basic import BasicTrainingStrategy
from fairing.builders.container_image_builder import ContainerImageBuilder
from fairing.metaparticle import MetaparticleClient
from fairing.utils import get_image_full

REPO_NAME = 'testrepo'
IMAGE_NAME = 'fairing-test'
IMAGE_TAG = 'test'

@pytest.fixture
def trainer():
    return Trainer(repository=REPO_NAME, image_name=IMAGE_NAME, image_tag=IMAGE_TAG)

@pytest.fixture
def mock_strategy():
    return Mock(spec=BasicTrainingStrategy)

@pytest.fixture
def mock_mp_client():
    return Mock(spec=MetaparticleClient)

@pytest.fixture
def mock_trainer():
    return Mock(spec=Trainer)

@pytest.fixture
def mock_builder():
    return Mock(spec=ContainerImageBuilder)

def test_compile_ast(trainer):
    trainer.fill_image_name_and_tag()
    svc, env = trainer.compile_ast()
    assert env == None
    assert len(svc['jobs']) == 1

    job = svc['jobs'][0]

    assert len(job['containers']) == 1
    assert job['containers'][0]['image'] == get_image_full(REPO_NAME, IMAGE_NAME, IMAGE_TAG)

def test_start_training(mock_strategy):
    # Start training should call exec_user_code method from the chosen strategy
    # with the user code as parameter

    # this object will stand in as user code
    fake_user_object = {'fake_prop': 'fake'}

    trainer = Trainer(repository=REPO_NAME,
                      image_name=IMAGE_NAME,
                      image_tag=IMAGE_TAG,
                      strategy=mock_strategy)

    trainer.start_training(fake_user_object)

    mock_strategy.exec_user_code.assert_called_with(fake_user_object)

def test_deploy_training(mock_builder, mock_mp_client, monkeypatch):
    monkeypatch.setattr(
        'fairing.train.MetaparticleClient', mock_mp_client)
    monkeypatch.setattr(
        'fairing.train.get_container_builder', lambda x: mock_builder)

    trainer = Trainer(repository=REPO_NAME)
    trainer.deploy_training(stream_logs=False)

    # Deploy should first generate a Dockerfile, build and finally push the image
    mock_builder.execute.assert_called_once()

@pytest.mark.parametrize("is_runtime_phase", [True, False])
def test_train(is_runtime_phase, mock_trainer, monkeypatch):
    monkeypatch.setattr('fairing.train.Trainer', mock_trainer)
    monkeypatch.setattr('fairing.train.is_runtime_phase',

             lambda: is_runtime_phase)

    mock_inst = mock_trainer()

    @Train(repository=REPO_NAME)
    class TestModel(object):
        def train(self):
            pass

    model = TestModel()
    model.train()

    # When running outside the metaparticle container (so on a user system),
    # when train() is called, it should build the container and deploy the code into
    # a metaparticle container.
    # Once running in a metaparticle container, train() should instead route to
    # the actual user code (through start_training)
    if is_runtime_phase:
        mock_inst.start_training.assert_called_once()
    else:
        mock_inst.deploy_training.assert_called_once()


import pytest

from encyclopaedia.encyclopaedia import Encyclopaedia
from encyclopaedia.encentry import EncEntry

def test_setting_entry_number():
    """
    When some entries have a pre-determined number,
    And some do not,
    Then the ones that do not should select the first available number.
    """

    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        number=4,
        name="Apple",
        text=["Test Text"],
    )

    for x in range(0, 5):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
        )

    assert 6 == e.number

enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

def test_clear_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

    enc.ClearFilter()()

    assert False is enc.filtering
    assert [apple, banana, cantaloupe, cucumber] == enc.current_entries

def test_reverse_alphabetical_sorting():
    enc = Encyclopaedia(sorting_mode=Encyclopaedia.SORT_REVERSE_ALPHABETICAL)

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
    )

    assert [cantaloupe, banana, apple] == enc.all_entries

def test_unlock_callback():
    enc = Encyclopaedia()

    global baz
    baz = 0

    @enc.on("entry_unlocked")
    def foobar(enc):
        global baz
        baz += 1

    e = EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=True,
    )

    # Unlock the first entry
    e.locked = False
    assert e.locked is False

    assert 1 == baz

def test_duplicate_entry_numbers():
    """When trying to assign a number to an EncEntry that's already taken,
    an Exception should be thrown.
    """
    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    with pytest.raises(ValueError) as e:
        EncEntry(
            parent=enc,
            number=1,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    message = '1 is already taken.'
    assert message == str(e.value)

def test_set_entry_show_locked_buttons():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_buttons is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 9
    """
    enc = Encyclopaedia(show_locked_buttons=True, show_locked_entry=False)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 9 == enc.current_position

def test_set_entry_show_locked_entry():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_entry is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 14
    """
    enc = Encyclopaedia(show_locked_buttons=False, show_locked_entry=True)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 14 == enc.current_position

def test_current_entries_show_unlocked():
    """With filtering off and show_locked_buttons set to False,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.unlocked_entries.
    """

    enc = Encyclopaedia()

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert expected_list == enc.current_entries

def test_current_entries_show_all():
    """With filtering off and show_locked_buttons set to True,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.all_entries.
    """

    enc = Encyclopaedia(show_locked_buttons=True)

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )
        expected_list.append(e)

    assert expected_list == enc.current_entries

def test_percentage_unlocked():
    """Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

def test_percentage_unlocked_empty():
    """When an encyclopaedia is empty,
    Then accessing percentage_unlocked raises an Exception.
    And provide a readable error message.
    """
    enc = Encyclopaedia()

    with pytest.raises(ZeroDivisionError) as e:
        enc.percentage_unlocked

    message = 'Cannot calculate percentage unlocked of empty Encyclopaedia'
    assert message == str(e.value)

def test_word_count():
    """When checking the word count of an Encyclopaedia,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
        )

    assert 10 == enc.word_count

def test_word_count_locked():
    """When checking the word count of an Encyclopaedia,
    And entries are locked,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 10 == enc.word_count


"""Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

import pytest

from encyclopaedia.encyclopaedia import Encyclopaedia
from encyclopaedia.encentry import EncEntry

def test_setting_entry_number():
    """
    When some entries have a pre-determined number,
    And some do not,
    Then the ones that do not should select the first available number.
    """

    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        number=4,
        name="Apple",
        text=["Test Text"],
    )

    for x in range(0, 5):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
        )

    assert 6 == e.number

def test_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

def test_clear_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

    enc.ClearFilter()()

    assert False is enc.filtering
    assert [apple, banana, cantaloupe, cucumber] == enc.current_entries

def test_reverse_alphabetical_sorting():
    enc = Encyclopaedia(sorting_mode=Encyclopaedia.SORT_REVERSE_ALPHABETICAL)

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
    )

    assert [cantaloupe, banana, apple] == enc.all_entries

def test_unlock_callback():
    enc = Encyclopaedia()

    global baz
    baz = 0

    @enc.on("entry_unlocked")
    def foobar(enc):
        global baz
        baz += 1

    e = EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=True,
    )

    # Unlock the first entry
    e.locked = False
    assert e.locked is False

    assert 1 == baz

def test_duplicate_entry_numbers():
    """When trying to assign a number to an EncEntry that's already taken,
    an Exception should be thrown.
    """
    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    with pytest.raises(ValueError) as e:
        EncEntry(
            parent=enc,
            number=1,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    message = '1 is already taken.'
    assert message == str(e.value)

def test_set_entry_show_locked_buttons():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_buttons is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 9
    """
    enc = Encyclopaedia(show_locked_buttons=True, show_locked_entry=False)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 9 == enc.current_position

def test_set_entry_show_locked_entry():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_entry is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 14
    """
    enc = Encyclopaedia(show_locked_buttons=False, show_locked_entry=True)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 14 == enc.current_position

def test_current_entries_show_unlocked():
    """With filtering off and show_locked_buttons set to False,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.unlocked_entries.
    """

    enc = Encyclopaedia()

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert expected_list == enc.current_entries

def test_current_entries_show_all():
    """With filtering off and show_locked_buttons set to True,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.all_entries.
    """

    enc = Encyclopaedia(show_locked_buttons=True)

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )
        expected_list.append(e)

    assert expected_list == enc.current_entries

def test_percentage_unlocked():

def test_percentage_unlocked_empty():
    """When an encyclopaedia is empty,
    Then accessing percentage_unlocked raises an Exception.
    And provide a readable error message.
    """
    enc = Encyclopaedia()

    with pytest.raises(ZeroDivisionError) as e:
        enc.percentage_unlocked

    message = 'Cannot calculate percentage unlocked of empty Encyclopaedia'
    assert message == str(e.value)

def test_word_count():
    """When checking the word count of an Encyclopaedia,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
        )

    assert 10 == enc.word_count

def test_word_count_locked():
    """When checking the word count of an Encyclopaedia,
    And entries are locked,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 10 == enc.word_count


"""Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

def test_percentage_unlocked_empty():
    """When an encyclopaedia is empty,
    Then accessing percentage_unlocked raises an Exception.
    And provide a readable error message.
    """
    enc = Encyclopaedia()

    with pytest.raises(ZeroDivisionError) as e:
        enc.percentage_unlocked

    message = 'Cannot calculate percentage unlocked of empty Encyclopaedia'
    assert message == str(e.value)

def test_word_count():
    """When checking the word count of an Encyclopaedia,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
        )

    assert 10 == enc.word_count

def test_word_count_locked():
    """When checking the word count of an Encyclopaedia,
    And entries are locked,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 10 == enc.word_count


for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

import pytest

from encyclopaedia.encyclopaedia import Encyclopaedia
from encyclopaedia.encentry import EncEntry

def test_setting_entry_number():
    """
    When some entries have a pre-determined number,
    And some do not,
    Then the ones that do not should select the first available number.
    """

    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        number=4,
        name="Apple",
        text=["Test Text"],
    )

    for x in range(0, 5):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
        )

    assert 6 == e.number

def test_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

def test_clear_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

    enc.ClearFilter()()

    assert False is enc.filtering
    assert [apple, banana, cantaloupe, cucumber] == enc.current_entries

def test_reverse_alphabetical_sorting():
    enc = Encyclopaedia(sorting_mode=Encyclopaedia.SORT_REVERSE_ALPHABETICAL)

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
    )

    assert [cantaloupe, banana, apple] == enc.all_entries

def test_unlock_callback():
    enc = Encyclopaedia()

    global baz
    baz = 0

    @enc.on("entry_unlocked")
    def foobar(enc):
        global baz
        baz += 1

    e = EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=True,
    )

    # Unlock the first entry
    e.locked = False
    assert e.locked is False

    assert 1 == baz

def test_duplicate_entry_numbers():
    """When trying to assign a number to an EncEntry that's already taken,
    an Exception should be thrown.
    """
    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    with pytest.raises(ValueError) as e:
        EncEntry(
            parent=enc,
            number=1,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    message = '1 is already taken.'
    assert message == str(e.value)

def test_set_entry_show_locked_buttons():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_buttons is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 9
    """
    enc = Encyclopaedia(show_locked_buttons=True, show_locked_entry=False)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 9 == enc.current_position

def test_set_entry_show_locked_entry():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_entry is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 14
    """
    enc = Encyclopaedia(show_locked_buttons=False, show_locked_entry=True)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 14 == enc.current_position

def test_current_entries_show_unlocked():
    """With filtering off and show_locked_buttons set to False,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.unlocked_entries.
    """

    enc = Encyclopaedia()

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert expected_list == enc.current_entries

def test_current_entries_show_all():
    """With filtering off and show_locked_buttons set to True,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.all_entries.
    """

    enc = Encyclopaedia(show_locked_buttons=True)

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )
        expected_list.append(e)

    assert expected_list == enc.current_entries

def test_percentage_unlocked():
    """Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

def test_percentage_unlocked_empty():
    """When an encyclopaedia is empty,
    Then accessing percentage_unlocked raises an Exception.
    And provide a readable error message.
    """
    enc = Encyclopaedia()

    with pytest.raises(ZeroDivisionError) as e:
        enc.percentage_unlocked

    message = 'Cannot calculate percentage unlocked of empty Encyclopaedia'
    assert message == str(e.value)

def test_word_count():
    """When checking the word count of an Encyclopaedia,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
        )

    assert 10 == enc.word_count

def test_word_count_locked():
    """When checking the word count of an Encyclopaedia,
    And entries are locked,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 10 == enc.word_count


for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

import pytest

from encyclopaedia.encyclopaedia import Encyclopaedia
from encyclopaedia.encentry import EncEntry

def test_setting_entry_number():
    """
    When some entries have a pre-determined number,
    And some do not,
    Then the ones that do not should select the first available number.
    """

    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        number=4,
        name="Apple",
        text=["Test Text"],
    )

    for x in range(0, 5):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
        )

    assert 6 == e.number

def test_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

def test_clear_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

    enc.ClearFilter()()

    assert False is enc.filtering
    assert [apple, banana, cantaloupe, cucumber] == enc.current_entries

def test_reverse_alphabetical_sorting():
    enc = Encyclopaedia(sorting_mode=Encyclopaedia.SORT_REVERSE_ALPHABETICAL)

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
    )

    assert [cantaloupe, banana, apple] == enc.all_entries

def test_unlock_callback():
    enc = Encyclopaedia()

    global baz
    baz = 0

    @enc.on("entry_unlocked")
    def foobar(enc):
        global baz
        baz += 1

    e = EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=True,
    )

    # Unlock the first entry
    e.locked = False
    assert e.locked is False

    assert 1 == baz

def test_duplicate_entry_numbers():
    """When trying to assign a number to an EncEntry that's already taken,
    an Exception should be thrown.
    """
    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    with pytest.raises(ValueError) as e:
        EncEntry(
            parent=enc,
            number=1,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    message = '1 is already taken.'
    assert message == str(e.value)

def test_set_entry_show_locked_buttons():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_buttons is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 9
    """
    enc = Encyclopaedia(show_locked_buttons=True, show_locked_entry=False)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 9 == enc.current_position

def test_set_entry_show_locked_entry():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_entry is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 14
    """
    enc = Encyclopaedia(show_locked_buttons=False, show_locked_entry=True)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 14 == enc.current_position

def test_current_entries_show_unlocked():
    """With filtering off and show_locked_buttons set to False,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.unlocked_entries.
    """

    enc = Encyclopaedia()

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert expected_list == enc.current_entries

def test_current_entries_show_all():
    """With filtering off and show_locked_buttons set to True,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.all_entries.
    """

    enc = Encyclopaedia(show_locked_buttons=True)

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )
        expected_list.append(e)

    assert expected_list == enc.current_entries

def test_percentage_unlocked():
    """Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )


import pytest

from encyclopaedia.encyclopaedia import Encyclopaedia
from encyclopaedia.encentry import EncEntry

def test_setting_entry_number():
    """
    When some entries have a pre-determined number,
    And some do not,
    Then the ones that do not should select the first available number.
    """

    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        number=4,
        name="Apple",
        text=["Test Text"],
    )

    for x in range(0, 5):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
        )

    assert 6 == e.number

def test_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

def test_clear_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

    enc.ClearFilter()()

    assert False is enc.filtering
    assert [apple, banana, cantaloupe, cucumber] == enc.current_entries

def test_reverse_alphabetical_sorting():
    enc = Encyclopaedia(sorting_mode=Encyclopaedia.SORT_REVERSE_ALPHABETICAL)

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
    )

    assert [cantaloupe, banana, apple] == enc.all_entries

def test_unlock_callback():
    enc = Encyclopaedia()

    global baz
    baz = 0

    @enc.on("entry_unlocked")
    def foobar(enc):
        global baz
        baz += 1

    e = EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=True,
    )

    # Unlock the first entry
    e.locked = False
    assert e.locked is False

    assert 1 == baz

def test_duplicate_entry_numbers():
    """When trying to assign a number to an EncEntry that's already taken,
    an Exception should be thrown.
    """
    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    with pytest.raises(ValueError) as e:
        EncEntry(
            parent=enc,
            number=1,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    message = '1 is already taken.'
    assert messag

def test_set_entry_show_locked_buttons():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_buttons is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 9
    """
    enc = Encyclopaedia(show_locked_buttons=True, show_locked_entry=False)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 9 == enc.current_position

def test_set_entry_show_locked_entry():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_entry is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 14
    """
    enc = Encyclopaedia(show_locked_buttons=False, show_locked_entry=True)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 14 == enc.current_position

def test_current_entries_show_unlocked():
    """With filtering off and show_locked_buttons set to False,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.unlocked_entries.
    """

    enc = Encyclopaedia()

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert expected_list == enc.current_entries

def test_current_entries_show_all():
    """With filtering off and show_locked_buttons set to True,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.all_entries.
    """

    enc = Encyclopaedia(show_locked_buttons=True)

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )
        expected_list.append(e)

    assert expected_list == enc.current_entries

def test_percentage_unlocked():
    """Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

def test_percentage_unlocked_empty():
    """When an encyclopaedia is empty,
    Then accessing percentage_unlocked raises an Exception.
    And provide a readable error message.
    """
    enc = Encyclopaedia()

    with pytest.raises(ZeroDivisionError) as e:
        enc.percentage_unlocked

    message = 'Cannot calculate percentage unlocked of empty Encyclopaedia'
    assert message == str(e.value)

def test_word_count():
    """When checking the word count of an Encyclopaedia,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
        )

    assert 10 == enc.word_count

def test_word_count_locked():
    """When checking the word count of an Encyclopaedia,
    And entries are locked,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 10 == enc.word_count


    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 10 == enc.word_count

import pytest

from encyclopaedia.encyclopaedia import Encyclopaedia
from encyclopaedia.encentry import EncEntry

def test_setting_entry_number():
    """
    When some entries have a pre-determined number,
    And some do not,
    Then the ones that do not should select the first available number.
    """

    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        number=4,
        name="Apple",
        text=["Test Text"],
    )

    for x in range(0, 5):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
        )

    assert 6 == e.number

def test_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

def test_clear_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

    enc.ClearFilter()()

    assert False is enc.filtering
    assert [apple, banana, cantaloupe, cucumber] == enc.current_entries

def test_reverse_alphabetical_sorting():
    enc = Encyclopaedia(sorting_mode=Encyclopaedia.SORT_REVERSE_ALPHABETICAL)

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
    )

    assert [cantaloupe, banana, apple] == enc.all_entries

def test_unlock_callback():
    enc = Encyclopaedia()

    global baz
    baz = 0

    @enc.on("entry_unlocked")
    def foobar(enc):
        global baz
        baz += 1

    e = EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=True,
    )

    # Unlock the first entry
    e.locked = False
    assert e.locked is False

    assert 1 == baz

def test_duplicate_entry_numbers():
    """When trying to assign a number to an EncEntry that's already taken,
    an Exception should be thrown.
    """
    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    with pytest.raises(ValueError) as e:
        EncEntry(
            parent=enc,
            number=1,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    message = '1 is already taken.'
    assert message == str(e.value)

def test_set_entry_show_locked_buttons():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_buttons is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 9
    """
    enc = Encyclopaedia(show_locked_buttons=True, show_locked_entry=False)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 9 == enc.current_position

def test_set_entry_show_locked_entry():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_entry is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 14
    """
    enc = Encyclopaedia(show_locked_buttons=False, show_locked_entry=True)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 14 == enc.current_position

def test_current_entries_show_unlocked():
    """With filtering off and show_locked_buttons set to False,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.unlocked_entries.
    """

    enc = Encyclopaedia()

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert expected_list == enc.current_entries

def test_current_entries_show_all():
    """With filtering off and show_locked_buttons set to True,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.all_entries.
    """

    enc = Encyclopaedia(show_locked_buttons=True)

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )
        expected_list.append(e)

    assert expected_list == enc.current_entries

def test_percentage_unlocked():
    """Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

def test_percentage_unlocked_empty():
    """When an encyclopaedia is empty,
    Then accessing percentage_unlocked raises an Exception.
    And provide a readable error message.
    """
    enc = Encyclopaedia()

    with pytest.raises(ZeroDivisionError) as e:
        enc.percentage_unlocked

    message = 'Cannot calculate percentage unlocked of empty Encyclopaedia'
    assert message == str(e.value)

def test_word_count():
    """When checking the word count of an Encyclopaedia,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
        )

    assert 10 == enc.word_count

def test_word_count_locked():
    """When checking the word count of an Encyclopaedia,
    And entries are locked,
    Then the number returned is correct.
    """


import pytest

from encyclopaedia.encyclopaedia import Encyclopaedia
from encyclopaedia.encentry import EncEntry

def test_setting_entry_number():
    """
    When some entries have a pre-determined number,
    And some do not,
    Then the ones that do not should select the first available number.
    """

    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        number=4,
        name="Apple",
        text=["Test Text"],
    )

    for x in range(0, 5):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
        )

    assert 6 == e.number

def test_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

def test_clear_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

    enc.ClearFilter()()

    assert False is enc.filtering
    assert [apple, banana, cantaloupe, cucumber] == enc.current_entries

def test_reverse_alphabetical_sorting():
    enc = Encyclopaedia(sorting_mode=Encyclopaedia.SORT_REVERSE_ALPHABETICAL)

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
    )

    assert [cantaloupe, banana, apple] == enc.all_entries

def test_unlock_callback():
    enc = Encyclopaedia()

    global baz
    baz = 0

    @enc.on("entry_unlocked")
    def foobar(enc):
        global baz
        baz += 1

    e = EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=True,
    )

    # Unlock the first entry
    e.locked = False
    assert e.locked is False

    assert 1 == baz

def test_duplicate_entry_numbers():
    """When trying to assign a number to an EncEntry that's already taken,
    an Exception should be thrown.
    """
    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    with pytest.raises(ValueError) as e:
        EncEntry(
            parent=enc,
            number=1,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    message = '1 is already taken.'
    assert message == str(e.value)

def test_set_entry_show_locked_buttons():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_buttons is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 9
    """
    enc = Encyclopaedia(show_locked_buttons=True, show_locked_entry=False)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 9 == enc.current_position

def test_set_entry_show_locked_entry():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_entry is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 14
    """
    enc = Encyclopaedia(show_locked_buttons=False, show_locked_entry=True)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 14 == enc.current_position

def test_current_entries_show_unlocked():
    """With filtering off and show_locked_buttons set to False,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.unlocked_entries.
    """

    enc = Encyclopaedia()

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert expected_list == enc.current_entries

def test_current_entries_show_all():
    """With filtering off and show_locked_buttons set to True,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.all_entries.
    """

    enc = Encyclopaedia(show_locked_buttons=True)

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )
        expected_list.append(e)

    assert expected_list == enc.current_entries

def test_percentage_unlocked():
    """Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

def test_percentage_unlocked_empty():
    """When an encyclopaedia is empty,
    Then accessing percentage_unlocked raises an Exception.
    And provide a readable error message.
    """
    enc = Encyclopaedia()

    with pytest.raises(ZeroDivisionError) as e:
        enc.percentage_unlocked

    message = 'Cannot calculate percentage unlocked of empty Encyclopaedia'
    assert message == str(e.value)

def test_word_count():
    """When checking the word count of an Encyclopaedia,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
        )

    assert 10 == enc.word_count

def test_word_count_locked():
    """When checking the word count of an Encyclopaedia,
    And entries are locked,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()


import pytest

from encyclopaedia.encyclopaedia import Encyclopaedia
from encyclopaedia.encentry import EncEntry

def test_setting_entry_number():
    """
    When some entries have a pre-determined number,
    And some do not,
    Then the ones that do not should select the first available number.
    """

    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        number=4,
        name="Apple",
        text=["Test Text"],
    )

    for x in range(0, 5):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
        )

    assert 6 == e.number

def test_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

def test_clear_filtering():
    enc = Encyclopaedia()

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
        subject="Fruits"
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
        subject="Fruits"
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
        subject="Fruits"
    )

    cucumber = EncEntry(
        parent=enc,
        name="Cucumber",
        text=["Test Text"],
        subject="Vegetables"
    )

    enc.FilterBySubject("Fruits")()

    assert "Fruits" == enc.filtering
    assert [apple, banana, cantaloupe] == enc.current_entries

    enc.ClearFilter()()

    assert False is enc.filtering
    assert [apple, banana, cantaloupe, cucumber] == enc.current_entries

def test_reverse_alphabetical_sorting():
    enc = Encyclopaedia(sorting_mode=Encyclopaedia.SORT_REVERSE_ALPHABETICAL)

    apple = EncEntry(
        parent=enc,
        name="Apple",
        text=["Test Text"],
    )

    banana = EncEntry(
        parent=enc,
        name="Banana",
        text=["Test Text"],
    )

    cantaloupe = EncEntry(
        parent=enc,
        name="Cantaloupe",
        text=["Test Text"],
    )

    assert [cantaloupe, banana, apple] == enc.all_entries

def test_unlock_callback():
    enc = Encyclopaedia()

    global baz
    baz = 0

    @enc.on("entry_unlocked")
    def foobar(enc):
        global baz
        baz += 1

    e = EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=True,
    )

    # Unlock the first entry
    e.locked = False
    assert e.locked is False

    assert 1 == baz

def test_duplicate_entry_numbers():
    """When trying to assign a number to an EncEntry that's already taken,
    an Exception should be thrown.
    """
    enc = Encyclopaedia()

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    EncEntry(
        parent=enc,
        name="Test Name",
        text=["Test Text"],
        locked=False
    )

    with pytest.raises(ValueError) as e:
        EncEntry(
            parent=enc,
            number=1,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    message = '1 is already taken.'
    assert message == str(e.value)

def test_set_entry_show_locked_buttons():
    """Given an E

ncyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_buttons is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 9
    """
    enc = Encyclopaedia(show_locked_buttons=True, show_locked_entry=False)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 9 == enc.current_position

def test_set_entry_show_locked_entry():
    """Given an Encyclopaedia with 10 unlocked entries and 5 locked entries,
    And show_locked_entry is true,
    When I set the 10th unlocked entry to be the active entry,
    Then the entry should be marked as viewed,
    And the entry should be the active entry,
    And the Encyclopaedia's current_position should be 14
    """
    enc = Encyclopaedia(show_locked_buttons=False, show_locked_entry=True)

    for x in range(0, 5):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    for x in range(5, 10):
        EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=True
        )

    for x in range(10, 15):
        e = EncEntry(
            parent=enc,
            name="Test Name {}".format(x + 1),
            text=["Test Text"],
            locked=False
        )

    # Use the last unlocked Entry created for the test.
    enc.SetEntry(e)()

    assert e == enc.active
    assert e.viewed
    assert 14 == enc.current_position

def test_current_entries_show_unlocked():
    """With filtering off and show_locked_buttons set to False,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.unlocked_entries.
    """

    enc = Encyclopaedia()

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert expected_list == enc.current_entries

def test_current_entries_show_all():
    """With filtering off and show_locked_buttons set to True,
    Encyclopaedia.current_entries property should return
    Encyclopaedia.all_entries.
    """

    enc = Encyclopaedia(show_locked_buttons=True)

    expected_list = []

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )
        expected_list.append(e)

    for x in range(5):
        e = EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )
        expected_list.append(e)

    assert expected_list == enc.current_entries

def test_percentage_unlocked():
    """Base unit test for the
    Encyclopaedia.percentage_unlocked property.
    """

    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=False
        )

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 50.00 == enc.percentage_unlocked

def test_percentage_unlocked_empty():
    """When an encyclopaedia is empty,
    Then accessing percentage_unlocked raises an Exception.
    And provide a readable error message.
    """
    enc = Encyclopaedia()

    with pytest.raises(ZeroDivisionError) as e:
        enc.percentage_unlocked

    message = 'Cannot calculate percentage unlocked of empty Encyclopaedia'
    assert message == str(e.value)

def test_word_count():
    """When checking the word count of an Encyclopaedia,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
        )

    assert 10 == enc.word_count

def test_word_count_locked():
    """When checking the word count of an Encyclopaedia,
    And entries are locked,
    Then the number returned is correct.
    """
    enc = Encyclopaedia()

    for x in range(5):
        EncEntry(
            parent=enc,
            name="Test Name",
            text=["Test Text"],
            locked=True
        )

    assert 10 == enc.word_count


from typing import Callable

import jax.numpy as jnp
import jax.random as jr
import pytest
from tensorflow_probability.substrates.jax import distributions as tfd

from gpjax import Dataset, Prior
from gpjax.kernels import RBF, to_spectral
from gpjax.likelihoods import Gaussian, Bernoulli
from gpjax.parameters import initialise, complete
from gpjax.sampling import random_variable, sample

@pytest.mark.parametrize("n", [1, 10])
def test_prior_random_variable(n):
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    D = Dataset(X=sample_points)
    params = initialise(RBF())
    rv = random_variable(f, params, D)
    assert isinstance(rv, tfd.MultivariateNormalFullCovariance)

@pytest.mark.parametrize("n", [1, 10])
def test_posterior_random_variable(n):
    f = Prior(kernel=RBF()) * Gaussian()
    x = jnp.linspace(-1.0, 1.0, 10).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(f)
    rv = random_variable(f, params, D)
    assert isinstance(rv, Callable)
    fstar = rv(sample_points)
    assert isinstance(fstar, tfd.MultivariateNormalFullCovariance)

@pytest.mark.parametrize("n", [1, 10])
def test_non_conjugate_rv(n):
    key = jr.PRNGKey(123)
    f = posterior = Prior(kernel=RBF()) * Bernoulli()
    x = jnp.sort(jr.uniform(key, shape=(n, 1), minval=-1.0, maxval=1.0), axis=0)
    y = 0.5 * jnp.sign(jnp.cos(3 * x + jr.normal(key, shape=x.shape) * 0.05)) + 0.5
    D = Dataset(X=x, y=y)

    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)

    hyperparams = {"lengthscale": jnp.array([1.0]), "variance": jnp.array([1.0])}
    params = complete(hyperparams, posterior, x.shape[0])
    rv = random_variable(f, params, D)
    assert isinstance(rv, Callable)
    fstar = rv(sample_points)
    assert isinstance(fstar, tfd.ProbitBernoulli)

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])

key = jr.PRNGKey(123)
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(RBF())
    samples = sample(key, f, params, sample_points, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_prior_sample_array(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    D = Dataset(X = sample_points)
    params = initialise(RBF())
    samples = sample(key, f, params, D, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_posterior_sample(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF()) * Gaussian()
    x = jnp.linspace(-1.0, 1.0, 10).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(f)
    rv = random_variable(f, params, D)(sample_points)
    samples = sample(key, rv, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

def test_spectral_sample():
    key = jr.PRNGKey(123)
    M = 10
    x = jnp.linspace(-1.0, 1.0, 20).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=50).reshape(-1, 1)
    kernel = to_spectral(RBF(), M)
    post = Prior(kernel=kernel) * Gaussian()
    params = initialise(key, post)
    sparams = {"basis_fns": params["basis_fns"]}
    del params["basis_fns"]
    posterior_rv = random_variable(post, params, D, static_params=sparams)(sample_points)
    assert isinstance(posterior_rv, tfd.Distribution)
    assert isinstance(posterior_rv, tfd.MultivariateNormalFullCovariance)


key = jr.PRNGKey(123)
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(RBF())
    samples = sample(key, f, params, sample_points, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

from typing import Callable

import jax.numpy as jnp
import jax.random as jr
import pytest
from tensorflow_probability.substrates.jax import distributions as tfd

from gpjax import Dataset, Prior
from gpjax.kernels import RBF, to_spectral
from gpjax.likelihoods import Gaussian, Bernoulli
from gpjax.parameters import initialise, complete
from gpjax.sampling import random_variable, sample

@pytest.mark.parametrize("n", [1, 10])
def test_prior_random_variable(n):
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    D = Dataset(X=sample_points)
    params = initialise(RBF())
    rv = random_variable(f, params, D)
    assert isinstance(rv, tfd.MultivariateNormalFullCovariance)

@pytest.mark.parametrize("n", [1, 10])
def test_posterior_random_variable(n):
    f = Prior(kernel=RBF()) * Gaussian()
    x = jnp.linspace(-1.0, 1.0, 10).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(f)
    rv = random_variable(f, params, D)
    assert isinstance(rv, Callable)
    fstar = rv(sample_points)
    assert isinstance(fstar, tfd.MultivariateNormalFullCovariance)

@pytest.mark.parametrize("n", [1, 10])
def test_non_conjugate_rv(n):
    key = jr.PRNGKey(123)
    f = posterior = Prior(kernel=RBF()) * Bernoulli()
    x = jnp.sort(jr.uniform(key, shape=(n, 1), minval=-1.0, maxval=1.0), axis=0)
    y = 0.5 * jnp.sign(jnp.cos(3 * x + jr.normal(key, shape=x.shape) * 0.05)) + 0.5
    D = Dataset(X=x, y=y)

    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)

    hyperparams = {"lengthscale": jnp.array([1.0]), "variance": jnp.array([1.0])}
    params = complete(hyperparams, posterior, x.shape[0])
    rv = random_variable(f, params, D)
    assert isinstance(rv, Callable)
    fstar = rv(sample_points)
    assert isinstance(fstar, tfd.ProbitBernoulli)

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_prior_sample(n, n_sample):

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_prior_sample_array(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    D = Dataset(X = sample_points)
    params = initialise(RBF())
    samples = sample(key, f, params, D, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_posterior_sample(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF()) * Gaussian()
    x = jnp.linspace(-1.0, 1.0, 10).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(f)
    rv = random_variable(f, params, D)(sample_points)
    samples = sample(key, rv, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

def test_spectral_sample():
    key = jr.PRNGKey(123)
    M = 10
    x = jnp.linspace(-1.0, 1.0, 20).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=50).reshape(-1, 1)
    kernel = to_spectral(RBF(), M)
    post = Prior(kernel=kernel) * Gaussian()
    params = initialise(key, post)
    sparams = {"basis_fns": params["basis_fns"]}
    del params["basis_fns"]
    posterior_rv = random_variable(post, params, D, static_params=sparams)(sample_points)
    assert isinstance(posterior_rv, tfd.Distribution)
    assert isinstance(posterior_rv, tfd.MultivariateNormalFullCovariance)


key = jr.PRNGKey(123)
    f = Prior(kernel=RBF()) * Gaussian()
    x = jnp.linspace(-1.0, 1.0, 10).reshape(-1, 1)
    y = jnp.sin(x)

from typing import Callable

import jax.numpy as jnp
import jax.random as jr
import pytest
from tensorflow_probability.substrates.jax import distributions as tfd

from gpjax import Dataset, Prior
from gpjax.kernels import RBF, to_spectral
from gpjax.likelihoods import Gaussian, Bernoulli
from gpjax.parameters import initialise, complete
from gpjax.sampling import random_variable, sample

@pytest.mark.parametrize("n", [1, 10])
def test_prior_random_variable(n):
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    D = Dataset(X=sample_points)
    params = initialise(RBF())
    rv = random_variable(f, params, D)
    assert isinstance(rv, tfd.MultivariateNormalFullCovariance)

@pytest.mark.parametrize("n", [1, 10])
def test_posterior_random_variable(n):
    f = Prior(kernel=RBF()) * Gaussian()
    x = jnp.linspace(-1.0, 1.0, 10).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(f)
    rv = random_variable(f, params, D)
    assert isinstance(rv, Callable)
    fstar = rv(sample_points)
    assert isinstance(fstar, tfd.MultivariateNormalFullCovariance)

@pytest.mark.parametrize("n", [1, 10])
def test_non_conjugate_rv(n):
    key = jr.PRNGKey(123)
    f = posterior = Prior(kernel=RBF()) * Bernoulli()
    x = jnp.sort(jr.uniform(key, shape=(n, 1), minval=-1.0, maxval=1.0), axis=0)
    y = 0.5 * jnp.sign(jnp.cos(3 * x + jr.normal(key, shape=x.shape) * 0.05)) + 0.5
    D = Dataset(X=x, y=y)

    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)

    hyperparams = {"lengthscale": jnp.array([1.0]), "variance": jnp.array([1.0])}
    params = complete(hyperparams, posterior, x.shape[0])
    rv = random_variable(f, params, D)
    assert isinstance(rv, Callable)
    fstar = rv(sample_points)
    assert isinstance(fstar, tfd.ProbitBernoulli)

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_prior_sample(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(RBF())
    samples = sample(key, f, params, sample_points, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_prior_sample_array(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    D = Dataset(X = sample_points)
    params = initialise(RBF())
    samples = sample(key, f, params, D, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_posterior_sample(n, n_sample):

    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(f)
    rv = random_variable(f, params, D)(sample_points)
    samples = sample(key, rv, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

def test_spectral_sample():
    key = jr.PRNGKey(123)
    M = 10
    x = jnp.linspace(-1.0, 1.0, 20).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=50).reshape(-1, 1)
    kernel = to_spectral(RBF(), M)
    post = Prior(kernel=kernel) * Gaussian()
    params = initialise(key, post)
    sparams = {"basis_fns": params["basis_fns"]}
    del params["basis_fns"]
    posterior_rv = random_variable(post, params, D, static_params=sparams)(sample_points)
    assert isinstance(posterior_rv, tfd.Distribution)
    assert isinstance(posterior_rv, tfd.MultivariateNormalFullCovariance)


from typing import Callable

import jax.numpy as jnp
import jax.random as jr
import pytest
from tensorflow_probability.substrates.jax import distributions as tfd

from gpjax import Dataset, Prior
from gpjax.kernels import RBF, to_spectral
from gpjax.likelihoods import Gaussian, Bernoulli
from gpjax.parameters import initialise, complete
from gpjax.sampling import random_variable, sample

@pytest.mark.parametrize("n", [1, 10])
def test_prior_random_variable(n):
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    D = Dataset(X=sample_points)
    params = initialise(RBF())
    rv = random_variable(f, params, D)
    assert isinstance(rv, tfd.MultivariateNormalFullCovariance)

@pytest.mark.parametrize("n", [1, 10])
def test_posterior_random_variable(n):
    f = Prior(kernel=RBF()) * Gaussian()
    x = jnp.linspace(-1.0, 1.0, 10).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(f)
    rv = random_variable(f, params, D)
    assert isinstance(rv, Callable)
    fstar = rv(sample_points)
    assert isinstance(fstar, tfd.MultivariateNormalFullCovariance)

@pytest.mark.parametrize("n", [1, 10])
def test_non_conjugate_rv(n):
    key = jr.PRNGKey(123)
    f = posterior = Prior(kernel=RBF()) * Bernoulli()
    x = jnp.sort(jr.uniform(key, shape=(n, 1), minval=-1.0, maxval=1.0), axis=0)
    y = 0.5 * jnp.sign(jnp.cos(3 * x + jr.normal(key, shape=x.shape) * 0.05)) + 0.5
    D = Dataset(X=x, y=y)

    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)

    hyperparams = {"lengthscale": jnp.array([1.0]), "variance": jnp.array([1.0])}
    params = complete(hyperparams, posterior, x.shape[0])
    rv = random_variable(f, params, D)
    assert isinstance(rv, Callable)
    fstar = rv(sample_points)
    assert isinstance(fstar, tfd.ProbitBernoulli)

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_prior_sample(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    params = initialise(RBF())
    samples = sample(key, f, params, sample_points, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_prior_sample_array(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF())
    sample_points = jnp.linspace(-1.0, 1.0, num=n).reshape(-1, 1)
    D = Dataset(X = sample_points)
    params = initialise(RBF())
    samples = sample(key, f, params, D, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

@pytest.mark.parametrize("n_sample", [1, 10])
@pytest.mark.parametrize("n", [1, 10])
def test_posterior_sample(n, n_sample):
    key = jr.PRNGKey(123)
    f = Prior(kernel=RBF()) * Gaussian()
    x = jnp.linspace(-1.0, 1.0, 10).reshape(-1, 1)
    y = jnp.sin(x)

    rv = random_variable(f, params, D)(sample_points)
    samples = sample(key, rv, n_samples=n_sample)
    assert samples.shape == (n_sample, sample_points.shape[0])

def test_spectral_sample():
    key = jr.PRNGKey(123)
    M = 10
    x = jnp.linspace(-1.0, 1.0, 20).reshape(-1, 1)
    y = jnp.sin(x)
    D = Dataset(X=x, y=y)
    sample_points = jnp.linspace(-1.0, 1.0, num=50).reshape(-1, 1)
    kernel = to_spectral(RBF(), M)
    post = Prior(kernel=kernel) * Gaussian()
    params = initialise(key, post)
    sparams = {"basis_fns": params["basis_fns"]}
    del params["basis_fns"]
    posterior_rv = random_variable(post, params, D, static_params=sparams)(sample_points)
    assert isinstance(posterior_rv, tfd.Distribution)
    assert isinstance(posterior_rv, tfd.MultivariateNormalFullCovariance)