pincerna 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rubocop.yml +77 -0
  4. data/.travis-gemfile +17 -0
  5. data/.travis.yml +7 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +3 -0
  8. data/Gemfile +23 -0
  9. data/LICENSE.md +21 -0
  10. data/README.md +211 -0
  11. data/Rakefile +45 -0
  12. data/bin/pincernad +56 -0
  13. data/docs/Pincerna.html +130 -0
  14. data/docs/Pincerna/Base.html +3051 -0
  15. data/docs/Pincerna/Bookmark.html +523 -0
  16. data/docs/Pincerna/Cache.html +767 -0
  17. data/docs/Pincerna/ChromeBookmark.html +308 -0
  18. data/docs/Pincerna/CurrencyConversion.html +589 -0
  19. data/docs/Pincerna/FirefoxBookmark.html +328 -0
  20. data/docs/Pincerna/Ip.html +1017 -0
  21. data/docs/Pincerna/Map.html +399 -0
  22. data/docs/Pincerna/SafariBookmark.html +308 -0
  23. data/docs/Pincerna/Server.html +673 -0
  24. data/docs/Pincerna/Translation.html +517 -0
  25. data/docs/Pincerna/UnitConversion.html +1042 -0
  26. data/docs/Pincerna/Version.html +189 -0
  27. data/docs/Pincerna/Vpn.html +561 -0
  28. data/docs/Pincerna/Weather.html +837 -0
  29. data/docs/_index.html +298 -0
  30. data/docs/class_list.html +54 -0
  31. data/docs/css/common.css +1 -0
  32. data/docs/css/full_list.css +57 -0
  33. data/docs/css/style.css +338 -0
  34. data/docs/file.README.html +327 -0
  35. data/docs/file_list.html +56 -0
  36. data/docs/frames.html +28 -0
  37. data/docs/index.html +327 -0
  38. data/docs/js/app.js +214 -0
  39. data/docs/js/full_list.js +178 -0
  40. data/docs/js/jquery.js +4 -0
  41. data/docs/method_list.html +389 -0
  42. data/docs/top-level-namespace.html +112 -0
  43. data/icon.png +0 -0
  44. data/images/chrome.png +0 -0
  45. data/images/currency.png +0 -0
  46. data/images/firefox.png +0 -0
  47. data/images/map.png +0 -0
  48. data/images/network.png +0 -0
  49. data/images/safari.png +0 -0
  50. data/images/translate.png +0 -0
  51. data/images/unit.png +0 -0
  52. data/images/vpn.png +0 -0
  53. data/images/weather.png +0 -0
  54. data/info.plist +961 -0
  55. data/it.cowtech.pincernad.plist +19 -0
  56. data/lib/pincerna.rb +30 -0
  57. data/lib/pincerna/base.rb +258 -0
  58. data/lib/pincerna/bookmark.rb +80 -0
  59. data/lib/pincerna/cache.rb +61 -0
  60. data/lib/pincerna/chrome_bookmark.rb +40 -0
  61. data/lib/pincerna/currency_conversion.rb +134 -0
  62. data/lib/pincerna/firefox_bookmark.rb +92 -0
  63. data/lib/pincerna/ip.rb +135 -0
  64. data/lib/pincerna/map.rb +30 -0
  65. data/lib/pincerna/safari_bookmark.rb +40 -0
  66. data/lib/pincerna/server.rb +85 -0
  67. data/lib/pincerna/translation.rb +67 -0
  68. data/lib/pincerna/unit_conversion.rb +120 -0
  69. data/lib/pincerna/version.rb +24 -0
  70. data/lib/pincerna/vpn.rb +74 -0
  71. data/lib/pincerna/weather.rb +188 -0
  72. data/pincerna.alfredworkflow +0 -0
  73. data/pincerna.gemspec +36 -0
  74. data/pincerna.sh +9 -0
  75. data/spec/cassettes/Pincerna_CurrencyConversion/_perform_filtering/should_return_valid_values.yml +38 -0
  76. data/spec/cassettes/Pincerna_Ip/_get_local_addresses/should_return_a_list_of_addresses.yml +47 -0
  77. data/spec/cassettes/Pincerna_Ip/_get_public_address/should_return_public_IP_address.yml +44 -0
  78. data/spec/cassettes/Pincerna_Translation/_perform_filtering/should_default_from_English_to_the_given_language_when_only_one_is_present.yml +124 -0
  79. data/spec/cassettes/Pincerna_Translation/_perform_filtering/should_query_Google_Translate_for_sentences_returning_no_alternatives.yml +51 -0
  80. data/spec/cassettes/Pincerna_Translation/_perform_filtering/should_query_Google_Translate_for_single_words.yml +71 -0
  81. data/spec/cassettes/Pincerna_Weather/_get_forecast/should_append_name.yml +177 -0
  82. data/spec/cassettes/Pincerna_Weather/_get_forecast/should_get_correct_forecasts.yml +339 -0
  83. data/spec/cassettes/Pincerna_Weather/_lookup_places/should_return_an_existing_WOEID_without_making_any_request.yml +56 -0
  84. data/spec/cassettes/Pincerna_Weather/_lookup_places/should_search_for_places.yml +189 -0
  85. data/spec/cassettes/Pincerna_Weather/_perform_filtering/should_get_forecast.yml +56 -0
  86. data/spec/coverage_helper.rb +44 -0
  87. data/spec/pincerna/base_spec.rb +166 -0
  88. data/spec/pincerna/bookmark_spec.rb +65 -0
  89. data/spec/pincerna/cache_spec.rb +88 -0
  90. data/spec/pincerna/chrome_bookmark_spec.rb +114 -0
  91. data/spec/pincerna/currency_conversion_spec.rb +46 -0
  92. data/spec/pincerna/firefox_bookmark_spec.rb +46 -0
  93. data/spec/pincerna/ip_spec.rb +194 -0
  94. data/spec/pincerna/map_spec.rb +24 -0
  95. data/spec/pincerna/safari_bookmark_spec.rb +237 -0
  96. data/spec/pincerna/server_spec.rb +108 -0
  97. data/spec/pincerna/translation_spec.rb +55 -0
  98. data/spec/pincerna/unit_conversion_spec.rb +98 -0
  99. data/spec/pincerna/vpn_spec.rb +68 -0
  100. data/spec/pincerna/weather_spec.rb +131 -0
  101. data/spec/spec_helper.rb +48 -0
  102. metadata +283 -0
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
+ # Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
5
+ #
6
+
7
+ require "spec_helper"
8
+
9
+ describe Pincerna::CurrencyConversion do
10
+ subject { Pincerna::CurrencyConversion.new("QUERY", "yml") }
11
+
12
+ describe "matching" do
13
+ it "should match valid queries" do
14
+ allow_any_instance_of(Pincerna::CurrencyConversion).to receive(:perform_filtering) { |*args| args }
15
+ allow_any_instance_of(Pincerna::CurrencyConversion).to receive(:process_results) { |*args| args }
16
+
17
+ expect(Pincerna::CurrencyConversion.new("123 EUR to GBP", "yml").filter).to eq_as_yaml([[123.0, "EUR", "GBP", false]])
18
+ expect(Pincerna::CurrencyConversion.new("-123.45 eur usd", "yml").filter).to eq_as_yaml([[-123.45, "EUR", "USD", false]])
19
+ expect(Pincerna::CurrencyConversion.new("123 EUR to GBP with rate", "yml").filter).to eq_as_yaml([[123.0, "EUR", "GBP", true]])
20
+ end
21
+
22
+ it "should not match invalid queries" do
23
+ expect_any_instance_of(Pincerna::CurrencyConversion).not_to receive(:perform_filtering)
24
+ expect_any_instance_of(Pincerna::CurrencyConversion).not_to receive(:process_results)
25
+
26
+ expect(Pincerna::CurrencyConversion.new("12A3 EUR to GBP", "yml").filter).to eq_as_yaml([])
27
+ end
28
+ end
29
+
30
+ describe "#perform_filtering", :vcr, :synchronous do
31
+ it "should return valid values" do
32
+ expect(subject.perform_filtering(123.45, "EUR", "USD", "RATE")).to eq({value: 123.45, from: "EUR", to: "USD", result: 163.756, rate: 1.327, with_rate: "RATE"})
33
+ end
34
+ end
35
+
36
+ describe "#process_results" do
37
+ before(:each) do
38
+ @value = {value: 123.45, from: "EUR", to: "USD", result: 163.892, rate: 1.328, with_rate: nil}
39
+ end
40
+
41
+ it "should correctly prepare results" do
42
+ expect(subject.process_results(@value)).to eq([{title: "123.45 EUR = 163.892 USD", arg: "123.45", subtitle: "Action this item to copy the converted amount on the clipboard.", icon: Pincerna::CurrencyConversion::ICON}])
43
+ expect(subject.process_results(@value.merge(with_rate: true))).to eq([{title: "123.45 EUR = 163.892 USD (1 EUR = 1.328 USD)", arg: "123.45", subtitle: "Action this item to copy the converted amount on the clipboard.", icon: Pincerna::CurrencyConversion::ICON}])
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
+ # Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
5
+ #
6
+
7
+ require "spec_helper"
8
+
9
+ describe Pincerna::FirefoxBookmark do
10
+ subject { Pincerna::FirefoxBookmark.new("QUERY", "yml") }
11
+
12
+ describe "#firefox_bookmarks" do
13
+ before(:each) do
14
+ @sqlite = <<EOSQLITE
15
+ #{Pincerna::FirefoxBookmark::QUERIES.first}
16
+ NAME 1|URL 1|4
17
+ NAME 2|URL 2|4
18
+ NAME|3|URL 3|3
19
+ NAME 4|URL 4|2
20
+ #{Pincerna::FirefoxBookmark::QUERIES.last}
21
+ BookmarksBar|1|0
22
+ BookmarksMenu|2|0
23
+ FOLDER 1|3|1
24
+ FOLDER|2|4|3
25
+ EOSQLITE
26
+ end
27
+
28
+ it "should call sqlite4 to get latest bookmarks" do
29
+ expect(Dir).to receive(:glob).with(File.expand_path("~/Library/Application Support/Firefox/Profiles") + "/*.default").and_return(["FIRST", "SECOND"])
30
+ expect(subject).to receive(:execute_command).with("/usr/bin/sqlite3", "-echo", "FIRST/places.sqlite", Pincerna::FirefoxBookmark::QUERIES.join("; "))
31
+ subject.read_bookmarks
32
+ end
33
+
34
+ it "should return the correct list of bookmarks" do
35
+ expect(subject.instance_variable_set(:@bookmarks, []))
36
+ allow(subject).to receive(:execute_command).and_return(@sqlite)
37
+ subject.read_bookmarks
38
+ expect(subject.instance_variable_get(:@bookmarks)).to eq([
39
+ {name: "NAME 1", url: "URL 1", path: " \u2192 BookmarksBar \u2192 FOLDER 1 \u2192 FOLDER|2"},
40
+ {name: "NAME 2", url: "URL 2", path: " \u2192 BookmarksBar \u2192 FOLDER 1 \u2192 FOLDER|2"},
41
+ {name: "NAME|3", url: "URL 3", path: " \u2192 BookmarksBar \u2192 FOLDER 1"},
42
+ {name: "NAME 4", url: "URL 4", path: " \u2192 BookmarksMenu"}
43
+ ])
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,194 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
+ # Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
5
+ #
6
+
7
+ require "spec_helper"
8
+
9
+ describe Pincerna::Ip do
10
+ subject { Pincerna::Ip.new("", "yml") }
11
+
12
+ before(:each) do
13
+ @ifconfig = <<EOIP
14
+ lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
15
+ options=3<RXCSUM,TXCSUM>
16
+ inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
17
+ inet 127.0.0.1 netmask 0xff000000
18
+ inet6 ::1 prefixlen 128
19
+ gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
20
+ stf0: flags=0<> mtu 1280
21
+ en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
22
+ options=2b<RXCSUM,TXCSUM,VLAN_HWTAGGING,TSO4>
23
+ ether 11:22:33:44:55:66
24
+ media: autoselect (none)
25
+ status: inactive
26
+ en1: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
27
+ ether 11:22:33:44:55:66
28
+ inet6 fe80::6aa8:6dff:fe2e:5afc%en1 prefixlen 64 scopeid 0x5
29
+ inet 192.168.1.21 netmask 0xffffff00 broadcast 192.168.1.255
30
+ media: autoselect
31
+ status: active
32
+ fw0: flags=8822<BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 4078
33
+ lladdr 11:22:33:44:55:66:77:88
34
+ media: autoselect <full-duplex>
35
+ status: inactive
36
+ p2p0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 2304
37
+ ether 11:22:33:44:55:66
38
+ media: autoselect
39
+ status: inactive
40
+ utun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1380
41
+ inet6 fe80::b5bc:eb1b:ee64:cd82%utun0 prefixlen 64 scopeid 0x8
42
+ inet6 fd3e:ebdd:9d87:a608:b5bc:eb1b:ee64:cd82 prefixlen 64
43
+ EOIP
44
+
45
+ @networksetup = <<EONAMES
46
+
47
+ Hardware Port: Bluetooth DUN
48
+ Device: Bluetooth-Modem
49
+ Ethernet Address: N/A
50
+
51
+ Hardware Port: Ethernet
52
+ Device: en0
53
+ Ethernet Address: 11:22:33:44:55:66
54
+
55
+ Hardware Port: FireWire
56
+ Device: fw0
57
+ Ethernet Address: 11:22:33:44:55:66:77:88
58
+
59
+ Hardware Port: Wi-Fi
60
+ Device: en1
61
+ Ethernet Address: 11:22:33:44:55:66
62
+
63
+ Hardware Port: Bluetooth PAN
64
+ Device: en2
65
+ Ethernet Address: N/A
66
+
67
+ VLAN Configurations
68
+ ===================
69
+ EONAMES
70
+
71
+ allow_any_instance_of(Pincerna::Ip).to receive(:execute_command) { |*args| args[0] == "/sbin/ifconfig" ? @ifconfig : @networksetup }
72
+ end
73
+
74
+ describe "matching" do
75
+ it "should allow both empty and present queries" do
76
+ allow_any_instance_of(Pincerna::Ip).to receive(:perform_filtering) { |args| [args] }
77
+ allow_any_instance_of(Pincerna::Ip).to receive(:process_results) { |args| args }
78
+
79
+ expect(Pincerna::Ip.new("QUERY", "yml").filter).to eq_as_yaml(["QUERY"])
80
+ expect(Pincerna::Ip.new("", "yml").filter).to eq_as_yaml([""])
81
+ end
82
+ end
83
+
84
+ describe "#perform_filtering" do
85
+ before(:each) do
86
+ allow(subject).to receive(:get_public_address).and_return({interface: nil, address: "8.8.8.8"})
87
+ end
88
+
89
+ describe "should return list of IPs" do
90
+ it "with no query" do
91
+ expect(subject.perform_filtering("")).to eq([
92
+ {interface: nil, address: "8.8.8.8"},
93
+ {interface: "Loopback (lo0)", address: "127.0.0.1"},
94
+ {interface: "Loopback (lo0)", address: "::1"},
95
+ {interface: "Loopback (lo0)", address: "fe80::1%lo0"},
96
+ {interface: "Wi-Fi (en1)", address: "192.168.1.21"},
97
+ {interface: "Wi-Fi (en1)", address: "fe80::6aa8:6dff:fe2e:5afc%en1"},
98
+ {interface: "utun0", address: "fd3e:ebdd:9d87:a608:b5bc:eb1b:ee64:cd82"},
99
+ {interface: "utun0", address: "fe80::b5bc:eb1b:ee64:cd82%utun0"}
100
+ ])
101
+ end
102
+
103
+ it "with query" do
104
+ expect(subject.perform_filtering("p")).to eq([
105
+ {interface: nil, address: "8.8.8.8"},
106
+ {interface: "Loopback (lo0)", address: "127.0.0.1"},
107
+ {interface: "Loopback (lo0)", address: "::1"},
108
+ {interface: "Loopback (lo0)", address: "fe80::1%lo0"}
109
+ ])
110
+
111
+ subject.instance_variable_set(:@interface_filter, nil)
112
+ expect(subject.perform_filtering("wi")).to eq([
113
+ {interface: "Wi-Fi (en1)", address: "192.168.1.21"},
114
+ {interface: "Wi-Fi (en1)", address: "fe80::6aa8:6dff:fe2e:5afc%en1"}
115
+ ])
116
+ end
117
+ end
118
+ end
119
+
120
+ describe "#process_results" do
121
+ before(:each) do
122
+ @value = [{interface: "INTERFACE", address: "IP 1"}, {interface: nil, address: "IP 2"}]
123
+ end
124
+
125
+ it "should correctly prepare results" do
126
+ expect(subject.process_results(@value)).to eq([
127
+ {title: "INTERFACE IP: IP 1", arg: "IP 1", subtitle: "Action this item to copy the IP on the clipboard.", icon: Pincerna::Ip::ICON},
128
+ {title: "Public IP: IP 2", arg: "IP 2", subtitle: "Action this item to copy the IP on the clipboard.", icon: Pincerna::Ip::ICON}
129
+ ])
130
+ end
131
+ end
132
+
133
+ describe "#get_local_addresses", :vcr do
134
+ before(:each) do
135
+ subject.instance_variable_set(:@interface_filter, /.*/i)
136
+ expect(subject).to receive(:get_interfaces_names).and_return({"en0" => "Ethernet", "fw0" => "FireWire", "en1" => "Wi-Fi", "en2" => "Bluetooth PAN", "lo0" => "Loopback"})
137
+ expect(subject).to receive(:execute_command).with("/sbin/ifconfig").and_return(@ifconfig)
138
+ end
139
+
140
+ it "should return a list of addresses" do
141
+ expect(subject.get_local_addresses).to eq([
142
+ {interface: "Loopback (lo0)", address: "fe80::1%lo0"},
143
+ {interface: "Loopback (lo0)", address: "127.0.0.1"},
144
+ {interface: "Loopback (lo0)", address: "::1"},
145
+ {interface: "Wi-Fi (en1)", address: "fe80::6aa8:6dff:fe2e:5afc%en1"},
146
+ {interface: "Wi-Fi (en1)", address: "192.168.1.21"},
147
+ {interface: "utun0", address: "fe80::b5bc:eb1b:ee64:cd82%utun0"},
148
+ {interface: "utun0", address: "fd3e:ebdd:9d87:a608:b5bc:eb1b:ee64:cd82"}
149
+ ])
150
+ end
151
+ end
152
+
153
+ describe "#get_public_address", :vcr, :synchronous do
154
+ it "should return public IP address" do
155
+ address = subject.get_public_address
156
+
157
+ expect(address.keys).to eq([:interface, :address])
158
+ expect(address[:interface]).to be_nil
159
+ expect(address[:address]).to eq("8.8.8.8")
160
+ end
161
+ end
162
+
163
+ describe "#compare_ip_classes" do
164
+ it "should compare IP classes" do
165
+ expect(subject.compare_ip_classes("127.0.0.1", "::1")).to eq(-1)
166
+ expect(subject.compare_ip_classes("::1", "::fe80:aabb")).to eq(0)
167
+ expect(subject.compare_ip_classes("::1", "127.0.0.1")).to eq(1)
168
+ end
169
+ end
170
+
171
+ describe "#compare_ip_addresses" do
172
+ it "should correctly compare IP addresses" do
173
+ expect(subject.compare_ip_addresses("127.0.0.1", "::1")).to eq(-1)
174
+ expect(subject.compare_ip_addresses("::1", "127.0.0.1")).to eq(1)
175
+ expect(subject.compare_ip_addresses("127.0.0.1", "192.168.0.1")).to eq(-1)
176
+ expect(subject.compare_ip_addresses("192.168.0.0", "192.168.0.1")).to eq(-1)
177
+ expect(subject.compare_ip_addresses("192.168.0.1", "192.168.0.1")).to eq(0)
178
+ expect(subject.compare_ip_addresses("127.0.0.1", "10.0.0.1")).to eq(1)
179
+ expect(subject.compare_ip_addresses("::1", "::fe80:aabb")).to eq(-1)
180
+ expect(subject.compare_ip_addresses("::fe80:aabe", "::fe80:aabd")).to eq(1)
181
+ expect(subject.compare_ip_addresses("::fe80:aaaa", "::fe80:aaaa")).to eq(0)
182
+ end
183
+ end
184
+
185
+ describe "#get_interfaces_names" do
186
+ before(:each) do
187
+ expect(subject).to receive(:execute_command).with("/usr/sbin/networksetup", "-listallhardwareports").and_return(@networksetup)
188
+ end
189
+
190
+ it "should return the current names of system interfaces" do
191
+ expect(subject.get_interfaces_names).to eq({"en0" => "Ethernet", "fw0" => "FireWire", "en1" => "Wi-Fi", "en2" => "Bluetooth PAN", "lo0" => "Loopback"})
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
+ # Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
5
+ #
6
+
7
+ require "spec_helper"
8
+
9
+ describe Pincerna::Map do
10
+ subject { Pincerna::Map.new("QUERY", "yml") }
11
+
12
+ describe "#perform_filtering" do
13
+ it "should simply return the query" do
14
+ expect(subject.perform_filtering("QUERY")).to eq({query: "QUERY"})
15
+ end
16
+ end
17
+
18
+ describe "#process_results" do
19
+ it "should correctly prepare results" do
20
+ expect(subject.process_results({query: "San Mateo, CA"})).to eq([{title: "View location on Google Maps", arg: "San+Mateo%2C+CA", subtitle: "Action this item to open Google Maps in the browser.", icon: Pincerna::Map::ICON}])
21
+ expect(subject.process_results({query: "-123.45,67.89"})).to eq([{title: "View coordinates on Google Maps", arg: "-123.45%2C67.89", subtitle: "Action this item to open Google Maps in the browser.", icon: Pincerna::Map::ICON}])
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,237 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the pincerna gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
+ # Licensed under the MIT license, which can be found at https://choosealicense.com/licenses/mit.
5
+ #
6
+
7
+ require "spec_helper"
8
+
9
+ describe Pincerna::SafariBookmark do
10
+ subject { Pincerna::SafariBookmark.new("QUERY", "yml") }
11
+
12
+ describe "#read_bookmarks" do
13
+ before(:each) do
14
+ @plutil = <<EOPLUTIL
15
+ <?xml version="1.0" encoding="UTF-8"?>
16
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
17
+ <plist version="1.0">
18
+ <dict>
19
+ <key>Children</key>
20
+ <array>
21
+ <dict>
22
+ <key>Title</key>
23
+ <string>History</string>
24
+ <key>WebBookmarkIdentifier</key>
25
+ <string>History</string>
26
+ <key>WebBookmarkType</key>
27
+ <string>WebBookmarkTypeProxy</string>
28
+ <key>WebBookmarkUUID</key>
29
+ <string>CCC</string>
30
+ </dict>
31
+ <dict>
32
+ <key>Children</key>
33
+ <array>
34
+ <dict>
35
+ <key>Children</key>
36
+ <array>
37
+ <dict>
38
+ <key>Children</key>
39
+ <array>
40
+ <dict>
41
+ <key>Sync</key>
42
+ <dict>
43
+ <key>Key</key>
44
+ <string>"C=AAA"</string>
45
+ <key>ServerID</key>
46
+ <string>AAA</string>
47
+ </dict>
48
+ <key>URIDictionary</key>
49
+ <dict>
50
+ <key>title</key>
51
+ <string>NAME 1</string>
52
+ </dict>
53
+ <key>URLString</key>
54
+ <string>URL 1</string>
55
+ <key>WebBookmarkType</key>
56
+ <string>WebBookmarkTypeLeaf</string>
57
+ <key>WebBookmarkUUID</key>
58
+ <string>AAA</string>
59
+ </dict>
60
+
61
+ <dict>
62
+ <key>Sync</key>
63
+ <dict>
64
+ <key>Key</key>
65
+ <string>"C=AAA"</string>
66
+ <key>ServerID</key>
67
+ <string>AAA</string>
68
+ </dict>
69
+ <key>URIDictionary</key>
70
+ <dict>
71
+ <key>title</key>
72
+ <string>NAME 2</string>
73
+ </dict>
74
+ <key>URLString</key>
75
+ <string>URL 2</string>
76
+ <key>WebBookmarkType</key>
77
+ <string>WebBookmarkTypeLeaf</string>
78
+ <key>WebBookmarkUUID</key>
79
+ <string>AAA</string>
80
+ </dict>
81
+
82
+ </array>
83
+ <key>Sync</key>
84
+ <dict>
85
+ <key>Data</key>
86
+ <data>CCC</data>
87
+ <key>Key</key>
88
+ <string>AAA</string>
89
+ <key>ServerID</key>
90
+ <string>BBB</string>
91
+ </dict>
92
+ <key>Title</key>
93
+ <string>FOLDER 2</string>
94
+ <key>WebBookmarkType</key>
95
+ <string>WebBookmarkTypeList</string>
96
+ <key>WebBookmarkUUID</key>
97
+ <string>CCC</string>
98
+ </dict>
99
+
100
+ <dict>
101
+ <key>Sync</key>
102
+ <dict>
103
+ <key>Key</key>
104
+ <string>"C=AAA"</string>
105
+ <key>ServerID</key>
106
+ <string>AAA</string>
107
+ </dict>
108
+ <key>URIDictionary</key>
109
+ <dict>
110
+ <key>title</key>
111
+ <string>NAME 3</string>
112
+ </dict>
113
+ <key>URLString</key>
114
+ <string>URL 3</string>
115
+ <key>WebBookmarkType</key>
116
+ <string>WebBookmarkTypeLeaf</string>
117
+ <key>WebBookmarkUUID</key>
118
+ <string>AAA</string>
119
+ </dict>
120
+ </array>
121
+ <key>Sync</key>
122
+ <dict>
123
+ <key>Data</key>
124
+ <data>DDD</data>
125
+ <key>Key</key>
126
+ <string>CCC</string>
127
+ <key>ServerID</key>
128
+ <string>DDD</string>
129
+ </dict>
130
+ <key>Title</key>
131
+ <string>FOLDER 1</string>
132
+ <key>WebBookmarkType</key>
133
+ <string>WebBookmarkTypeList</string>
134
+ <key>WebBookmarkUUID</key>
135
+ <string>AAA</string>
136
+ </dict>
137
+ </array>
138
+ <key>Sync</key>
139
+ <dict>
140
+ <key>ServerID</key>
141
+ <string>CCC</string>
142
+ </dict>
143
+ <key>Title</key>
144
+ <string>BookmarksBar</string>
145
+ <key>WebBookmarkType</key>
146
+ <string>WebBookmarkTypeList</string>
147
+ <key>WebBookmarkUUID</key>
148
+ <string>DDD</string>
149
+ </dict>
150
+ <dict>
151
+ <key>Sync</key>
152
+ <dict>
153
+ <key>ServerID</key>
154
+ <string>CCC</string>
155
+ </dict>
156
+ <key>Title</key>
157
+ <string>BookmarksMenu</string>
158
+ <key>WebBookmarkType</key>
159
+ <string>WebBookmarkTypeList</string>
160
+ <key>WebBookmarkUUID</key>
161
+ <string>DDD</string>
162
+ <key>Children</key>
163
+ <array>
164
+ <dict>
165
+ <key>Sync</key>
166
+ <dict>
167
+ <key>Key</key>
168
+ <string>"C=AAA"</string>
169
+ <key>ServerID</key>
170
+ <string>AAA</string>
171
+ </dict>
172
+ <key>URIDictionary</key>
173
+ <dict>
174
+ <key>title</key>
175
+ <string>NAME 4</string>
176
+ </dict>
177
+ <key>URLString</key>
178
+ <string>URL 4</string>
179
+ <key>WebBookmarkType</key>
180
+ <string>WebBookmarkTypeLeaf</string>
181
+ <key>WebBookmarkUUID</key>
182
+ <string>AAA</string>
183
+ </dict>
184
+ </array>
185
+ </dict>
186
+ <dict>
187
+ <key>ShouldOmitFromUI</key>
188
+ <true/>
189
+ <key>Sync</key>
190
+ <dict>
191
+ <key>ServerID</key>
192
+ <string>CCC</string>
193
+ </dict>
194
+ <key>Title</key>
195
+ <string>com.apple.ReadingList</string>
196
+ <key>WebBookmarkType</key>
197
+ <string>WebBookmarkTypeList</string>
198
+ <key>WebBookmarkUUID</key>
199
+ <string>DDD</string>
200
+ </dict>
201
+ </array>
202
+ <key>Sync</key>
203
+ <dict>
204
+ <key>ServerData</key>
205
+ <data>BBB</data>
206
+ </dict>
207
+ <key>Title</key>
208
+ <string></string>
209
+ <key>WebBookmarkFileVersion</key>
210
+ <integer>1</integer>
211
+ <key>WebBookmarkType</key>
212
+ <string>WebBookmarkTypeList</string>
213
+ <key>WebBookmarkUUID</key>
214
+ <string>AAA</string>
215
+ </dict>
216
+ </plist>
217
+ EOPLUTIL
218
+ end
219
+
220
+ it "should call plutil to get latest bookmarks" do
221
+ expect(subject).to receive(:execute_command).with("/usr/bin/plutil", "-convert", "xml1", "-o", "-", File.expand_path("~/Library/Safari/Bookmarks.plist"))
222
+ subject.read_bookmarks
223
+ end
224
+
225
+ it "should return the correct list of bookmarks" do
226
+ expect(subject.instance_variable_set(:@bookmarks, []))
227
+ allow(subject).to receive(:execute_command).and_return(@plutil)
228
+ subject.read_bookmarks
229
+ expect(subject.instance_variable_get(:@bookmarks)).to eq([
230
+ {name: "NAME 1", url: "URL 1", path: " \u2192 BookmarksBar \u2192 FOLDER 1 \u2192 FOLDER 2"},
231
+ {name: "NAME 2", url: "URL 2", path: " \u2192 BookmarksBar \u2192 FOLDER 1 \u2192 FOLDER 2"},
232
+ {name: "NAME 3", url: "URL 3", path: " \u2192 BookmarksBar \u2192 FOLDER 1"},
233
+ {name: "NAME 4", url: "URL 4", path: " \u2192 BookmarksMenu"}
234
+ ])
235
+ end
236
+ end
237
+ end