Skip to content

API Reference

General-purpose Adaptive Random Testing helpers.

adaptive_random_testing

adaptive_random_testing(generate_candidate: Callable[[Random], str], evaluate: Callable[[str], R], *, pool_size: int = 10, max_iterations: int = 5, seed: Optional[int] = None, distance_fn: Callable[[str, str], int] = levenshtein_distance) -> List[AdaptiveSample[R]]

Run Adaptive Random Testing using FSCs to spread out sampled inputs.

Parameters:

Name Type Description Default
generate_candidate Callable[[Random], str]

Callable that accepts a Random instance and returns an input to test.

required
evaluate Callable[[str], R]

Callable invoked on each candidate; its return value is recorded.

required
pool_size int

Number of candidates generated per iteration to select the farthest one.

10
max_iterations int

Total samples to run.

5
seed Optional[int]

Optional seed to make sampling repeatable.

None
distance_fn Callable[[str, str], int]

Distance function used to measure spread between candidates.

levenshtein_distance

Returns:

Type Description
List[AdaptiveSample[R]]

A list of AdaptiveSample entries containing the candidate, distance to prior inputs,

List[AdaptiveSample[R]]

and the evaluation result.

Source code in src/adaptive_testing_tools/adaptive.py
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def adaptive_random_testing(
    generate_candidate: Callable[[random.Random], str],
    evaluate: Callable[[str], R],
    *,
    pool_size: int = 10,
    max_iterations: int = 5,
    seed: Optional[int] = None,
    distance_fn: Callable[[str, str], int] = levenshtein_distance,
) -> List[AdaptiveSample[R]]:
    """
    Run Adaptive Random Testing using FSCs to spread out sampled inputs.

    Args:
        generate_candidate: Callable that accepts a Random instance and returns an input to test.
        evaluate: Callable invoked on each candidate; its return value is recorded.
        pool_size: Number of candidates generated per iteration to select the farthest one.
        max_iterations: Total samples to run.
        seed: Optional seed to make sampling repeatable.
        distance_fn: Distance function used to measure spread between candidates.

    Returns:
        A list of AdaptiveSample entries containing the candidate, distance to prior inputs,
        and the evaluation result.
    """
    rng = random.Random(seed)
    tested: List[str] = []
    samples: List[AdaptiveSample] = []

    for iteration in range(1, max_iterations + 1):
        candidate = select_fscs_candidate(
            tested,
            lambda: generate_candidate(rng),
            pool_size=pool_size,
            distance_fn=distance_fn,
        )
        result = evaluate(candidate)
        distance = (
            min(distance_fn(candidate, seen) for seen in tested) if tested else None
        )
        tested.append(candidate)
        samples.append(
            AdaptiveSample(
                iteration=iteration,
                candidate=candidate,
                result=result,
                distance_to_previous=distance,
            )
        )
    return samples

levenshtein_distance

levenshtein_distance(a: str, b: str) -> int

Return Levenshtein edit distance using rapidfuzz when available.

Source code in src/adaptive_testing_tools/adaptive.py
15
16
17
18
19
def levenshtein_distance(a: str, b: str) -> int:
    """Return Levenshtein edit distance using rapidfuzz when available."""
    if _Levenshtein is not None:
        return int(_Levenshtein.distance(a, b))
    return _python_levenshtein(a, b)

select_fscs_candidate

select_fscs_candidate(previous: Sequence[str], generate_candidate: Callable[[], str], *, pool_size: int = 10, distance_fn: Callable[[str, str], int] = levenshtein_distance) -> str

Pick the candidate with the largest minimum distance to prior samples (FSCs).

FSCs = Fixed Size Candidate Set. A pool of random candidates is generated and the one farthest from all previously tested inputs is selected.

Source code in src/adaptive_testing_tools/adaptive.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def select_fscs_candidate(
    previous: Sequence[str],
    generate_candidate: Callable[[], str],
    *,
    pool_size: int = 10,
    distance_fn: Callable[[str, str], int] = levenshtein_distance,
) -> str:
    """
    Pick the candidate with the largest minimum distance to prior samples (FSCs).

    FSCs = Fixed Size Candidate Set. A pool of random candidates is generated and
    the one farthest from all previously tested inputs is selected.
    """
    if not previous:
        return generate_candidate()
    best_candidate: Optional[str] = None
    best_distance = -1
    for _ in range(pool_size):
        candidate = generate_candidate()
        distance = min(distance_fn(candidate, seen) for seen in previous)
        if distance > best_distance:
            best_candidate = candidate
            best_distance = distance
    return best_candidate if best_candidate is not None else generate_candidate()

Utilities for generating small random values for tests.

random_choice

random_choice(options: Sequence[T]) -> T

Return a random element from a non-empty sequence.

Source code in src/adaptive_testing_tools/generator.py
15
16
17
18
19
def random_choice(options: Sequence[T]) -> T:
    """Return a random element from a non-empty sequence."""
    if not options:
        raise ValueError("options must not be empty")
    return random.choice(options)

random_int

random_int(low: int = 0, high: int = 100) -> int

Return a random integer between low and high (inclusive).

Source code in src/adaptive_testing_tools/generator.py
10
11
12
def random_int(low: int = 0, high: int = 100) -> int:
    """Return a random integer between low and high (inclusive)."""
    return random.randint(low, high)

random_string

random_string(length: int = 8, alphabet: Iterable[str] = None) -> str

Return a random string of the given length.

Source code in src/adaptive_testing_tools/generator.py
22
23
24
25
26
27
def random_string(length: int = 8, alphabet: Iterable[str] = None) -> str:
    """Return a random string of the given length."""
    if length < 0:
        raise ValueError("length must be non-negative")
    chars = alphabet or (string.ascii_letters + string.digits)
    return "".join(random.choice(chars) for _ in range(length))