File size: 4,593 Bytes
f9609df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
"""
Unit tests for auth.py — pure/stdlib-only, no camera or webview needed.
Every test gets its own tmp_path as data_dir, so nothing here touches the
real users.json on disk.
"""

import os

import pytest

import auth


# --- password hashing -------------------------------------------------------

def test_hash_password_generates_random_salt():
    salt1, hash1 = auth._hash_password("hunter2")
    salt2, hash2 = auth._hash_password("hunter2")
    assert salt1 != salt2
    assert hash1 != hash2  # different salt -> different hash for the same password


def test_hash_password_reproducible_with_given_salt():
    salt, hash1 = auth._hash_password("hunter2")
    _, hash2 = auth._hash_password("hunter2", salt=salt)
    assert hash1 == hash2


def test_verify_password_accepts_correct_password():
    salt, hash_hex = auth._hash_password("correct horse battery staple")
    assert auth.verify_password("correct horse battery staple", salt, hash_hex) is True


def test_verify_password_rejects_wrong_password():
    salt, hash_hex = auth._hash_password("correct horse battery staple")
    assert auth.verify_password("wrong password", salt, hash_hex) is False


# --- create_user validation --------------------------------------------------

def test_create_user_rejects_empty_name(tmp_path):
    with pytest.raises(auth.AuthError):
        auth.create_user(str(tmp_path), "", "a@b.com", "password123")


def test_create_user_rejects_invalid_email(tmp_path):
    with pytest.raises(auth.AuthError):
        auth.create_user(str(tmp_path), "Aman", "not-an-email", "password123")


def test_create_user_rejects_short_password(tmp_path):
    with pytest.raises(auth.AuthError):
        auth.create_user(str(tmp_path), "Aman", "a@b.com", "short")


def test_create_user_rejects_duplicate_email_case_insensitive(tmp_path):
    auth.create_user(str(tmp_path), "Aman", "Aman@Example.com", "password123")
    with pytest.raises(auth.AuthError):
        auth.create_user(str(tmp_path), "Someone Else", "aman@example.com", "different123")


def test_create_user_returns_public_profile_without_secrets(tmp_path):
    profile = auth.create_user(str(tmp_path), "Aman", "aman@example.com", "password123")
    assert profile["name"] == "Aman"
    assert profile["email"] == "aman@example.com"
    assert "salt" not in profile
    assert "hash" not in profile
    assert "id" in profile
    assert profile["avatar"] == "A"


def test_create_user_persists_across_loads(tmp_path):
    auth.create_user(str(tmp_path), "Aman", "aman@example.com", "password123")
    users = auth.load_users(str(tmp_path))
    assert len(users) == 1
    record = next(iter(users.values()))
    assert record["email"] == "aman@example.com"
    assert "hash" in record  # stored on disk, just never returned to callers


# --- login --------------------------------------------------------------

def test_verify_login_succeeds_with_correct_password(tmp_path):
    created = auth.create_user(str(tmp_path), "Aman", "aman@example.com", "password123")
    profile = auth.verify_login(str(tmp_path), created["id"], "password123")
    assert profile["id"] == created["id"]


def test_verify_login_fails_with_wrong_password(tmp_path):
    created = auth.create_user(str(tmp_path), "Aman", "aman@example.com", "password123")
    with pytest.raises(auth.AuthError):
        auth.verify_login(str(tmp_path), created["id"], "wrong-password")


def test_verify_login_fails_for_unknown_user_id(tmp_path):
    with pytest.raises(auth.AuthError):
        auth.verify_login(str(tmp_path), "does-not-exist", "whatever")


def test_verify_login_fails_for_empty_password(tmp_path):
    created = auth.create_user(str(tmp_path), "Aman", "aman@example.com", "password123")
    with pytest.raises(auth.AuthError):
        auth.verify_login(str(tmp_path), created["id"], "")


# --- list_profiles / user_dir ------------------------------------------------

def test_list_profiles_sorted_by_name_and_excludes_secrets(tmp_path):
    auth.create_user(str(tmp_path), "Zara", "zara@example.com", "password123")
    auth.create_user(str(tmp_path), "Aman", "aman@example.com", "password123")
    profiles = auth.list_profiles(str(tmp_path))
    assert [p["name"] for p in profiles] == ["Aman", "Zara"]
    assert all("salt" not in p and "hash" not in p for p in profiles)


def test_list_profiles_empty_when_no_users_file(tmp_path):
    assert auth.list_profiles(str(tmp_path)) == []


def test_user_dir_is_nested_under_users(tmp_path):
    path = auth.user_dir(str(tmp_path), "abc123")
    assert path == os.path.join(str(tmp_path), "users", "abc123")