File size: 1,695 Bytes
24c5a49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import pytest

from tiny_computer_agent import ACTION_KINDS, ACTION_MENU, Action, ActionError, parse_action


def test_click_by_label():
    action = Action("click", label="Save")
    assert action.kind == "click"
    assert "label='Save'" in action.describe()


def test_click_by_pixels():
    assert Action("click", x=10, y=20).x == 10


@pytest.mark.parametrize(
    "kwargs, message",
    [
        ({"kind": "fly"}, "unknown action"),
        ({"kind": "click"}, "click needs a label"),
        ({"kind": "click", "x": -1, "y": 5}, "non-negative"),
        ({"kind": "type", "text": ""}, "type needs non-empty text"),
        ({"kind": "key"}, "key needs a chord"),
        ({"kind": "scroll", "amount": 0}, "non-zero amount"),
        ({"kind": "wait", "seconds": 0}, "positive number of seconds"),
    ],
)
def test_validation_rejects_bad_actions(kwargs, message):
    with pytest.raises(ActionError, match=message):
        Action(**kwargs)

    # the same rule must hold for anything a model sends back
    with pytest.raises(ActionError):
        parse_action(kwargs)


def test_parse_action_ignores_chatty_extra_keys():
    action = parse_action({"kind": "type", "text": "hello", "confidence": 0.9, "thought": "..."})
    assert action.text == "hello"


def test_parse_action_rejects_a_non_mapping():
    with pytest.raises(ActionError, match="expected a mapping"):
        parse_action(["click", "Save"])


def test_menu_documents_every_verb():
    for kind in ACTION_KINDS:
        assert f'"kind": "{kind}"' in ACTION_MENU


def test_round_trip_to_dict():
    action = Action("scroll", amount=-3, reason="more content below")
    assert parse_action(action.to_dict()).amount == -3