def test_deregister_component(component):
    """
    Make sure we can deregister components via name or class.
    """
    # deregister the component
    deregister_component(component=component)

    assert workflow_components.SmartsFilter() not in list_components()

    # now add it back
    register_component(component=workflow_components.SmartsFilter())
def test_smarts_filter_apply_parameters():
    """
    Make sure the environment filter is correctly identifying substructures.
    """

    filter = workflow_components.SmartsFilter()

    # this should only allow C, H, N, O containing molecules through similar to the element filter
    filter.allowed_substructures = ["[C:1]", "[c:1]", "[H:1]", "[O:1]", "[N:1]"]
    filter.filtered_substructures = ["[Cl:1]", "[F:1]", "[P:1]", "[Br:1]", "[S:1]", "[I:1]", "[B:1]"]
    allowed_elements = [1, 6, 7, 8]

    molecules = get_tautomers()

    result = filter.apply(molecules, processors=1)

    assert result.component_name == filter.component_name
    assert result.component_description == filter.dict()
    # make sure there are no unwanted elements in the pass set
    for molecule in result.molecules:
        for atom in molecule.atoms:
            assert atom.atomic_number in allowed_elements, print(molecule)

    for molecule in result.filtered:
        elements = set([atom.atomic_number for atom in molecule.atoms])
        assert sorted(elements) != sorted(allowed_elements)
def test_smarts_filter_validator():
    """
    Make sure the validator is checking the allowed and filtered fields have valid smirks strings.
    """

    from openforcefield.typing.chemistry import SMIRKSParsingError

    filter = workflow_components.SmartsFilter()

    with pytest.raises(SMIRKSParsingError):
        filter.allowed_substructures = [1, 2, 3, 4]

    with pytest.raises(SMIRKSParsingError):
        # bad string
        filter.allowed_substructures = ["fkebfsjb"]

    with pytest.raises(SMIRKSParsingError):
        # make sure each item is checked
        filter.allowed_substructures = ["[C:1]-[C:2]", "ksbfsb"]

    with pytest.raises(SMIRKSParsingError):
        # good smarts with no tagged atoms.
        filter.allowed_substructures = ["[C]=[C]"]

    # a good search string
    filter.allowed_substructures = ["[C:1]=[C:2]"]
    assert len(filter.allowed_substructures) == 1
def test_smarts_filter_apply_tag_torsions(tag_dihedrals):
    """
    Make sure that torsions in molecules are tagged if we supply a torsion smarts a pattern.
    """
    filter = workflow_components.SmartsFilter(tag_dihedrals=tag_dihedrals)

    # look for methyl torsions here
    filter.allowed_substructures = ["[*:1]-[*:2]-[#6H3:3]-[#1:4]"]

    molecules = get_tautomers()
    # this should filter and tag the dihedrals
    result = filter.apply(molecules, processors=1)
    for molecule in result.molecules:
        if tag_dihedrals:
            assert "dihedrals" in molecule.properties
            # make sure the torsion is connected
            torsions = molecule.properties["dihedrals"]
            for torsion in torsions.get_dihedrals:
                _ = check_torsion_connection(torsion=torsion.torsion1, molecule=molecule)
        else:
            assert "dihedrals" not in molecule.properties
def test_smarts_filter_apply_none():
    """
    Make sure we get the expected behaviour when we supply None as the filter list.
    """

    filter = workflow_components.SmartsFilter()

    filter.allowed_substructures = None

    molecules = get_tautomers()

    # this should allow all molecules through
    result = filter.apply(molecules=molecules, processors=1)

    assert len(result.molecules) == len(molecules)

    # now filter the molecule set again removing aromatic carbons
    filter.filtered_substructures = ["[c:1]"]

    result2 = filter.apply(molecules=result.molecules, processors=1)

    assert len(result2.molecules) != len(result.molecules)
    register_component(component=workflow_components.StandardConformerGenerator(), replace=True)


def test_register_component_error():
    """
    Make sure an error is raised if we try and register a component that is not a sub class of CustomWorkflowComponent.
    """
    # fake component
    charge_filter = {"component_name": "charge_filter"}

    with pytest.raises(InvalidWorkflowComponentError):
        register_component(component=charge_filter)


@pytest.mark.parametrize("component", [
    pytest.param(workflow_components.SmartsFilter(), id="Class instance"),
    pytest.param("SmartsFilter", id="Class name")
])
def test_deregister_component(component):
    """
    Make sure we can deregister components via name or class.
    """
    # deregister the component
    deregister_component(component=component)

    assert workflow_components.SmartsFilter() not in list_components()

    # now add it back
    register_component(component=workflow_components.SmartsFilter())