import pytest
import numpy as np

from foolbox.attacks import LinfinityBasicIterativeAttack
from foolbox.attacks import L1BasicIterativeAttack
from foolbox.attacks import L2BasicIterativeAttack
from foolbox.attacks import ProjectedGradientDescentAttack
from foolbox.attacks import RandomStartProjectedGradientDescentAttack
from foolbox.attacks import MomentumIterativeAttack

Attacks = [
    LinfinityBasicIterativeAttack,
    L1BasicIterativeAttack,
    L2BasicIterativeAttack,
    ProjectedGradientDescentAttack,
    RandomStartProjectedGradientDescentAttack,
    MomentumIterativeAttack,
]


def test_attack_no_binary_search(bn_adversarial_linf):
    adv = bn_adversarial_linf
    attack = LinfinityBasicIterativeAttack()
    attack(adv, binary_search=False)
    assert adv.image is not None
    assert adv.distance.value < np.inf


@pytest.mark.parametrize('Attack', Attacks)
def test_attack_linf(Attack, bn_adversarial_linf):
    adv = bn_adversarial_linf
    attack = Attack()
    attack(adv, binary_search=10)
    assert adv.image is not None
    assert adv.distance.value < np.inf


@pytest.mark.parametrize('Attack', Attacks)
def test_attack_l2(Attack, bn_adversarial):
    adv = bn_adversarial
    attack = Attack()
    attack(adv)
    assert adv.image is not None
    assert adv.distance.value < np.inf


@pytest.mark.parametrize('Attack', Attacks)
def test_attack_l1(Attack, bn_adversarial_mae):
    adv = bn_adversarial_mae
    attack = Attack()
    attack(adv)
    assert adv.image is not None
    assert adv.distance.value < np.inf


@pytest.mark.parametrize('Attack', Attacks)
def test_targeted_attack(Attack, bn_targeted_adversarial):
    adv = bn_targeted_adversarial
    attack = Attack()
    attack(adv)
    assert adv.image is not None
    assert adv.distance.value < np.inf


@pytest.mark.parametrize('Attack', Attacks)
def test_attack_gl(Attack, gl_bn_adversarial):
    adv = gl_bn_adversarial
    attack = Attack()
    attack(adv)
    assert adv.image is None
    assert adv.distance.value == np.inf

@@ -620,16 +620,36 @@
 y_search
+_and_no_return_early
 (bn_adve
@@ -773,16 +773,36 @@
 ch=False
+, return_early=False
 )%0A    as
@@ -2049,16 +2049,244 @@
 value == np.inf%0A
+%0A%0A@pytest.mark.parametrize('Attack', Attacks)%0Adef test_attack_impossible(Attack, bn_impossible):%0A    adv = bn_impossible%0A    attack = Attack()%0A    attack(adv)%0A    assert adv.image is None%0A    assert adv.distance.value == np.inf%0A

test attack failure and special cases