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
require_relative "../test_helper"
require "digest"
require "pathname"
require "tmpdir"
require "pro_tacts/contact"
class ContactTest < Minitest::Test
def with_contacts(files)
Dir.mktmpdir do |dir|
directory = Pathname.new(dir)
files.each { |name, content| File.write(directory / name, content) }
yield directory
end
end
def test_all_parses_every_contact
with_contacts({
"znorth.kdl" => "name \"Zed\"",
"aiden.kdl" => "name \"Aiden\"",
}) do |directory|
ids = ProTacts::Contact.all(directory).map { it.id }
assert_includes ids, "aiden"
assert_includes ids, "znorth"
end
end
def test_the_uid_comes_from_the_filename
with_contacts({"kqmtnwpxlrvszoyp.kdl" => "name \"Aiden\""}) do |directory|
assert_includes ProTacts::Contact.all(directory).first.vcard, "UID:kqmtnwpxlrvszoyp"
end
end
def test_the_etag_hashes_the_rendered_card
with_contacts({"aiden.kdl" => "name \"Aiden\""}) do |directory|
contact = ProTacts::Contact.all(directory).first
assert_equal %("#{Digest::SHA256.hexdigest(contact.vcard)}"), contact.etag
end
end
def test_the_etag_is_stable_across_parses_and_moves_with_content
with_contacts({"aiden.kdl" => "name \"Aiden\""}) do |directory|
etag = ProTacts::Contact.all(directory).first.etag
assert_equal etag, ProTacts::Contact.all(directory).first.etag
File.write(directory / "aiden.kdl", "name \"Aiden Smith\"")
refute_equal etag, ProTacts::Contact.all(directory).first.etag
end
end
def test_an_empty_directory_lists_no_contacts
with_contacts({}) do |directory|
assert_empty ProTacts::Contact.all(directory)
end
end
def test_dotfiles_are_ignored
with_contacts({
".DS_Store" => "junk",
"aiden.kdl" => "name \"Aiden\"",
}) do |directory|
assert_equal %w[aiden], ProTacts::Contact.all(directory).map { it.id }
end
end
def test_a_missing_directory_raises
error = assert_raises(Errno::ENOENT) do
ProTacts::Contact.all(Pathname.new(Dir.mktmpdir) / "nonexistent")
end
assert_match(/nonexistent/, error.message)
end
def test_non_kdl_files_raise
with_contacts({"notes.txt" => "hello"}) do |directory|
error = assert_raises(ArgumentError) { ProTacts::Contact.all(directory) }
assert_equal "invalid contact id: notes.txt", error.message
end
end
def test_filenames_that_are_not_ids_raise
with_contacts({"John Smith.kdl" => "name \"John\""}) do |directory|
error = assert_raises(ArgumentError) { ProTacts::Contact.all(directory) }
assert_equal "invalid contact id: John Smith", error.message
end
end
def test_unparseable_files_raise
with_contacts({"broken.kdl" => "contact {"}) do |directory|
assert_raises(KDL::ParseError) { ProTacts::Contact.all(directory) }
end
end
def test_files_whose_keys_are_not_contact_fields_raise
with_contacts({"person.kdl" => "person { name \"A\" }"}) do |directory|
error = assert_raises(ArgumentError) { ProTacts::Contact.all(directory) }
assert_equal "unknown key in contact: person", error.message
end
end
def test_empty_files_raise
with_contacts({"empty.kdl" => ""}) do |directory|
error = assert_raises(ArgumentError) { ProTacts::Contact.all(directory) }
assert_equal "contact requires a name", error.message
end
end
def test_files_whose_card_cannot_render_raise
with_contacts({"nameless.kdl" => "phone \"+1-555-1234\""}) do |directory|
error = assert_raises(ArgumentError) { ProTacts::Contact.all(directory) }
assert_equal "contact requires a name", error.message
end
end
end