browser.rb 0.16.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG +516 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +116 -0
- data/Rakefile +182 -0
- data/browser.rb.gemspec +54 -0
- data/lib/Browser/Base.rb +50 -0
- data/lib/Browser/Bookmark.rb +41 -0
- data/lib/Browser/Bookmarks.rb +112 -0
- data/lib/Browser/Brave.rb +16 -0
- data/lib/Browser/Chrome.rb +16 -0
- data/lib/Browser/Chromium.rb +16 -0
- data/lib/Browser/ChromiumBased.rb +48 -0
- data/lib/Browser/Firefox.rb +16 -0
- data/lib/Browser/FirefoxBased.rb +86 -0
- data/lib/Browser/History.rb +41 -0
- data/lib/Browser/Rendering.rb +108 -0
- data/lib/Browser/Safari.rb +48 -0
- data/lib/Browser/TorBrowser.rb +26 -0
- data/lib/Browser/Unreadable.rb +11 -0
- data/lib/Browser/VERSION.rb +6 -0
- data/lib/browser-classes.rb +12 -0
- data/lib/browser.rb +29 -0
- data/test/Browser/Bookmark_test.rb +72 -0
- data/test/Browser/Brave_test.rb +143 -0
- data/test/Browser/Chrome_test.rb +143 -0
- data/test/Browser/Chromium_test.rb +143 -0
- data/test/Browser/Firefox_test.rb +205 -0
- data/test/Browser/Rendering_test.rb +68 -0
- data/test/Browser/Safari_test.rb +152 -0
- data/test/Browser/TorBrowser_test.rb +147 -0
- data/test/browser_test.rb +33 -0
- data/test/fixtures/Brave_bookmarks.json +47 -0
- data/test/fixtures/ChromiumBased_history.sqlite +0 -0
- data/test/fixtures/Chromium_bookmarks.json +47 -0
- data/test/fixtures/FirefoxBased_places.sqlite +0 -0
- data/test/fixtures/Safari_bookmarks.plist +0 -0
- data/test/fixtures/Safari_history.sqlite +0 -0
- data/test/gemspec_test.rb +42 -0
- data/test/loading_test.rb +35 -0
- metadata +194 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Browser/Rendering.rb
|
|
2
|
+
# Browser::Rendering
|
|
3
|
+
|
|
4
|
+
# The renderers, once. CSV, JSON and a plist, each over records and their column
|
|
5
|
+
# names, which is the shape Bookmarks and History both arrive at: Bookmarks by
|
|
6
|
+
# flattening its tree, History from its query. Including it gives a class to_csv,
|
|
7
|
+
# to_json, to_plist, dump and readable?; the class supplies results, to_objects and
|
|
8
|
+
# column_names.
|
|
9
|
+
|
|
10
|
+
require 'csv'
|
|
11
|
+
require 'date'
|
|
12
|
+
require 'json'
|
|
13
|
+
require 'cfpropertylist'
|
|
14
|
+
|
|
15
|
+
require_relative './Unreadable'
|
|
16
|
+
|
|
17
|
+
class Browser
|
|
18
|
+
module Rendering
|
|
19
|
+
class CSV
|
|
20
|
+
def render
|
|
21
|
+
::CSV.generate do |csv|
|
|
22
|
+
csv << @column_names
|
|
23
|
+
rows.each{|row| csv << row}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def initialize(records, column_names)
|
|
30
|
+
@records = records
|
|
31
|
+
@column_names = column_names
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def rows
|
|
35
|
+
@records.collect{|record| record.values_at(*@column_names)}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class JSON
|
|
40
|
+
def render
|
|
41
|
+
@records.to_json
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def initialize(records)
|
|
47
|
+
@records = records
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class Plist
|
|
52
|
+
def render
|
|
53
|
+
list = CFPropertyList::List.new
|
|
54
|
+
list.value = CFPropertyList.guess(@records)
|
|
55
|
+
list.to_str(CFPropertyList::List::FORMAT_XML)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def initialize(records)
|
|
61
|
+
@records = records
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def to_csv
|
|
66
|
+
CSV.new(to_objects, column_names).render
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def to_json
|
|
70
|
+
JSON.new(to_objects).render
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def to_plist
|
|
74
|
+
Plist.new(to_objects).render
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def dump(format: :csv, filename: nil, path: '.')
|
|
78
|
+
full_path = (
|
|
79
|
+
if filename
|
|
80
|
+
filename.include?(File::SEPARATOR) ? filename : File.join(path, filename)
|
|
81
|
+
else
|
|
82
|
+
File.join(path, dump_filename(format))
|
|
83
|
+
end
|
|
84
|
+
)
|
|
85
|
+
File.write(full_path, public_send("to_#{format}"))
|
|
86
|
+
full_path
|
|
87
|
+
rescue Errno::ENOENT => e
|
|
88
|
+
raise "Cannot write to #{full_path}: #{e.message}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def readable?
|
|
92
|
+
results
|
|
93
|
+
true
|
|
94
|
+
rescue Browser::Unreadable
|
|
95
|
+
false
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def dump_filename(extension)
|
|
101
|
+
[@browser_instance.name, @browser_instance.profile_name, kind, Date.today].compact.join('_') + ".#{extension}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def kind
|
|
105
|
+
self.class.name.split('::').last
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Browser/Safari.rb
|
|
2
|
+
# Browser::Safari
|
|
3
|
+
|
|
4
|
+
require_relative './Base'
|
|
5
|
+
|
|
6
|
+
class Browser
|
|
7
|
+
class Safari < Base
|
|
8
|
+
DEFAULT_PROFILE_NAME = nil # Safari doesn't have profiles.
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
def bookmarks_location(profile_name: nil)
|
|
12
|
+
profile_name ||= DEFAULT_PROFILE_NAME
|
|
13
|
+
File.expand_path("#{root_path}/Bookmarks.plist")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def history_location(profile_name: nil)
|
|
17
|
+
profile_name ||= DEFAULT_PROFILE_NAME
|
|
18
|
+
File.expand_path("#{root_path}/History.db")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def root_path
|
|
24
|
+
"~/Library/Safari"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def profiles_path
|
|
28
|
+
nil # Safari doesn't have profiles.
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def bookmarks_format
|
|
32
|
+
:plist
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def history_format
|
|
36
|
+
:sqlite
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def bookmarks_sql
|
|
40
|
+
nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def history_sql
|
|
44
|
+
'SELECT history_items.id, history_items.url, history_visits.visit_time FROM history_items LEFT JOIN history_visits WHERE history_items.id = history_visits.history_item ORDER BY visit_time DESC;'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Browser/TorBrowser.rb
|
|
2
|
+
# Browser::TorBrowser
|
|
3
|
+
|
|
4
|
+
require_relative './FirefoxBased'
|
|
5
|
+
|
|
6
|
+
class Browser
|
|
7
|
+
class TorBrowser < FirefoxBased
|
|
8
|
+
class << self
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def root_path
|
|
12
|
+
"~/Library/Application Support/TorBrowser-Data"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Tor Browser keeps its profiles under Browser where Firefox uses Profiles.
|
|
16
|
+
def profiles_path
|
|
17
|
+
"#{root_path}/Browser"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# And its profiles.ini beside them, where Firefox keeps its own beside Profiles.
|
|
21
|
+
def profiles_ini_path
|
|
22
|
+
File.expand_path("#{profiles_path}/profiles.ini")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Browser/Unreadable.rb
|
|
2
|
+
# Browser::Unreadable
|
|
3
|
+
|
|
4
|
+
# Raised when a browser's data cannot be read: the file is not there, the browser
|
|
5
|
+
# has it locked, or the format library cannot open it. The underlying exception is
|
|
6
|
+
# available as #cause, which Ruby sets when this is raised from a rescue.
|
|
7
|
+
|
|
8
|
+
class Browser
|
|
9
|
+
class Unreadable < StandardError
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# browser-classes.rb
|
|
2
|
+
|
|
3
|
+
# Instead of writing Browser::Brave.new or Browser.new(:brave), write Brave.new.
|
|
4
|
+
|
|
5
|
+
require_relative './browser'
|
|
6
|
+
|
|
7
|
+
Brave = Browser::Brave
|
|
8
|
+
Chrome = Browser::Chrome
|
|
9
|
+
Chromium = Browser::Chromium
|
|
10
|
+
Firefox = Browser::Firefox
|
|
11
|
+
Safari = Browser::Safari
|
|
12
|
+
TorBrowser = Browser::TorBrowser
|
data/lib/browser.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# browser.rb
|
|
2
|
+
# Browser
|
|
3
|
+
|
|
4
|
+
require_relative './Browser/VERSION'
|
|
5
|
+
|
|
6
|
+
class Browser
|
|
7
|
+
LIST = %w{
|
|
8
|
+
Brave
|
|
9
|
+
Chrome
|
|
10
|
+
Chromium
|
|
11
|
+
Firefox
|
|
12
|
+
Safari
|
|
13
|
+
TorBrowser
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
Browser::LIST.each do |browser|
|
|
18
|
+
browser_filename = File.expand_path("#{__FILE__}/../Browser/#{browser}")
|
|
19
|
+
require browser_filename
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Browser
|
|
23
|
+
def self.new(name = nil, **options)
|
|
24
|
+
return super(**options) unless self == Browser
|
|
25
|
+
browser_name = LIST.detect{|browser| browser.downcase == name.to_s.downcase.delete('_')}
|
|
26
|
+
raise ArgumentError, "Unknown browser: #{name.inspect}." unless browser_name
|
|
27
|
+
const_get(browser_name).new(**options)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Bookmark_test.rb
|
|
2
|
+
|
|
3
|
+
gem 'minitest'
|
|
4
|
+
gem 'minitest-spec-context'
|
|
5
|
+
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
require 'minitest-spec-context'
|
|
8
|
+
require 'rspec/expectations/minitest_integration'
|
|
9
|
+
|
|
10
|
+
lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
|
|
11
|
+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
12
|
+
|
|
13
|
+
require 'browser'
|
|
14
|
+
|
|
15
|
+
describe Browser::Bookmark do
|
|
16
|
+
describe "#leaf? and #folder?" do
|
|
17
|
+
it "a bookmark with a url is a leaf" do
|
|
18
|
+
bookmark = Browser::Bookmark.new(title: 'Home', url: 'https://example.com/')
|
|
19
|
+
expect(bookmark.leaf?).to be(true)
|
|
20
|
+
expect(bookmark.folder?).to be(false)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "a bookmark without a url is a folder" do
|
|
24
|
+
folder = Browser::Bookmark.new(title: 'Bar', children: [])
|
|
25
|
+
expect(folder.folder?).to be(true)
|
|
26
|
+
expect(folder.leaf?).to be(false)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "#name" do
|
|
31
|
+
it "is the title unless given, which is what a browser stores where that differs from what it shows" do
|
|
32
|
+
expect(Browser::Bookmark.new(title: 'Bookmarks Menu').name).to eq('Bookmarks Menu')
|
|
33
|
+
expect(Browser::Bookmark.new(title: 'Bookmarks Menu', name: 'menu').name).to eq('menu')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe "#flatten" do
|
|
38
|
+
subject do
|
|
39
|
+
Browser::Bookmark.new(children: [
|
|
40
|
+
Browser::Bookmark.new(title: 'Bar', children: [
|
|
41
|
+
Browser::Bookmark.new(title: 'Home', url: 'https://example.com/'),
|
|
42
|
+
Browser::Bookmark.new(title: 'Work', children: [
|
|
43
|
+
Browser::Bookmark.new(title: 'Mail', url: 'https://mail.example.com/'),
|
|
44
|
+
]),
|
|
45
|
+
]),
|
|
46
|
+
Browser::Bookmark.new(title: 'Top', url: 'https://top.example.com/'),
|
|
47
|
+
Browser::Bookmark.new(title: 'Empty', children: []),
|
|
48
|
+
])
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "returns a record per leaf, and none for folders" do
|
|
52
|
+
expect(subject.flatten.length).to eq(3)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "carries the folder path each leaf sits under, nesting joined by /" do
|
|
56
|
+
expect(subject.flatten).to eq([
|
|
57
|
+
{title: 'Home', url: 'https://example.com/', folder: 'Bar'},
|
|
58
|
+
{title: 'Mail', url: 'https://mail.example.com/', folder: 'Bar/Work'},
|
|
59
|
+
{title: 'Top', url: 'https://top.example.com/', folder: ''},
|
|
60
|
+
])
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "the rootless, titleless node adds nothing to the path" do
|
|
64
|
+
expect(subject.flatten.first[:folder]).to eq('Bar')
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "an empty folder contributes no records" do
|
|
68
|
+
empty = Browser::Bookmark.new(title: 'Empty', children: [])
|
|
69
|
+
expect(empty.flatten).to eq([])
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Brave_test.rb
|
|
2
|
+
|
|
3
|
+
gem 'minitest'
|
|
4
|
+
gem 'minitest-spec-context'
|
|
5
|
+
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
require 'minitest-spec-context'
|
|
8
|
+
require 'rspec/expectations/minitest_integration'
|
|
9
|
+
|
|
10
|
+
lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
|
|
11
|
+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
12
|
+
|
|
13
|
+
require 'browser'
|
|
14
|
+
|
|
15
|
+
describe Browser::Brave do
|
|
16
|
+
let(:bookmarks_fixtures_location){File.expand_path("#{__FILE__}/../../fixtures/Brave_bookmarks.json")}
|
|
17
|
+
let(:history_fixtures_location){File.expand_path("#{__FILE__}/../../fixtures/ChromiumBased_history.sqlite")}
|
|
18
|
+
let(:expected_history_sql){'SELECT * FROM urls ORDER BY last_visit_time DESC;'}
|
|
19
|
+
|
|
20
|
+
describe Browser::Brave::DEFAULT_PROFILE_NAME do
|
|
21
|
+
let(:expected_default_profile_name){'Default'}
|
|
22
|
+
|
|
23
|
+
it "contains the correct default profile name" do
|
|
24
|
+
expect(Browser::Brave::DEFAULT_PROFILE_NAME).to eq(expected_default_profile_name)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "class methods" do
|
|
29
|
+
subject{Browser::Brave}
|
|
30
|
+
|
|
31
|
+
describe '.bookmarks_location' do
|
|
32
|
+
let(:expected_bookmarks_location){File.expand_path('~/Library/Application Support/BraveSoftware/Brave-Browser/Default/Bookmarks')}
|
|
33
|
+
|
|
34
|
+
it "contains the correct bookmarks location" do
|
|
35
|
+
expect(subject.bookmarks_location).to eq(expected_bookmarks_location)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe '.history_location' do
|
|
40
|
+
let(:expected_history_location){File.expand_path('~/Library/Application Support/BraveSoftware/Brave-Browser/Default/History')}
|
|
41
|
+
|
|
42
|
+
it "contains the correct history location" do
|
|
43
|
+
expect(subject.history_location).to eq(expected_history_location)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe ".bookmarks_sql" do
|
|
48
|
+
it "returns the bookmarks sql" do
|
|
49
|
+
expect(subject.send(:bookmarks_sql)).to be_nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe ".history_sql" do
|
|
54
|
+
it "returns the history sql" do
|
|
55
|
+
expect(subject.send(:history_sql)).to eq(expected_history_sql)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context "instance methods" do
|
|
61
|
+
subject{Browser::Brave.new(bookmarks_location: bookmarks_fixtures_location, history_location: history_fixtures_location)}
|
|
62
|
+
|
|
63
|
+
let(:browser_name){'Brave'}
|
|
64
|
+
let(:default_profile_name){'Default'}
|
|
65
|
+
let(:expected_history) do
|
|
66
|
+
[
|
|
67
|
+
{'id' => 1, 'url' => 'https://www.chromium.org/chromium-projects/', 'title' => 'Home', 'visit_count' => 3, 'typed_count' => 1, 'last_visit_time' => 13403232000000000, 'hidden' => 0},
|
|
68
|
+
{'id' => 2, 'url' => 'chrome://welcome/', 'title' => 'Welcome', 'visit_count' => 1, 'typed_count' => 0, 'last_visit_time' => 13403231000000000, 'hidden' => 0},
|
|
69
|
+
]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "#initialize" do
|
|
73
|
+
it "returns an instance of Browser" do
|
|
74
|
+
expect(subject).to be_a(Browser::Brave)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "assigns @bookmarks_location" do
|
|
78
|
+
expect(subject.instance_variable_get(:@bookmarks_location)).to eq(bookmarks_fixtures_location)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "assigns @history_location" do
|
|
82
|
+
expect(subject.instance_variable_get(:@history_location)).to eq(history_fixtures_location)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "takes the default profile name when none is given" do
|
|
86
|
+
expect(subject.profile_name).to eq(default_profile_name)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe "#name" do
|
|
91
|
+
it "returns name" do
|
|
92
|
+
expect(subject.name).to eq(browser_name)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
let(:expected_bookmarks) do
|
|
97
|
+
[
|
|
98
|
+
{title: 'Welcome to Brave', url: 'chrome://welcome/', folder: 'Bookmarks bar'},
|
|
99
|
+
]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe "#bookmarks" do
|
|
103
|
+
it "returns an instance of Browser::Bookmarks" do
|
|
104
|
+
expect(subject.bookmarks).to be_a(Browser::Bookmarks)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "returns the bookmarks" do
|
|
108
|
+
expect(subject.bookmarks.to_objects).to eq(expected_bookmarks)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "#history" do
|
|
113
|
+
it "returns an instance of Browser::History" do
|
|
114
|
+
expect(subject.history).to be_a(Browser::History)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "returns the history" do
|
|
118
|
+
expect(subject.history.to_json).to eq(expected_history.to_json)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe "#readable?" do
|
|
123
|
+
it "is true when the data is there" do
|
|
124
|
+
expect(subject.bookmarks.readable?).to be(true)
|
|
125
|
+
expect(subject.history.readable?).to be(true)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
context "WHEN the data is not there" do
|
|
130
|
+
subject{Browser::Brave.new(bookmarks_location: '/nonexistent/file', history_location: '/nonexistent/file')}
|
|
131
|
+
|
|
132
|
+
it "is not readable" do
|
|
133
|
+
expect(subject.bookmarks.readable?).to be(false)
|
|
134
|
+
expect(subject.history.readable?).to be(false)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "raises Browser::Unreadable" do
|
|
138
|
+
expect{subject.bookmarks.to_json}.to raise_error(Browser::Unreadable)
|
|
139
|
+
expect{subject.history.to_json}.to raise_error(Browser::Unreadable)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Chrome_test.rb
|
|
2
|
+
|
|
3
|
+
gem 'minitest'
|
|
4
|
+
gem 'minitest-spec-context'
|
|
5
|
+
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
require 'minitest-spec-context'
|
|
8
|
+
require 'rspec/expectations/minitest_integration'
|
|
9
|
+
|
|
10
|
+
lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
|
|
11
|
+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
12
|
+
|
|
13
|
+
require 'browser'
|
|
14
|
+
|
|
15
|
+
describe Browser::Chrome do
|
|
16
|
+
let(:bookmarks_fixtures_location){File.expand_path("#{__FILE__}/../../fixtures/Chromium_bookmarks.json")}
|
|
17
|
+
let(:history_fixtures_location){File.expand_path("#{__FILE__}/../../fixtures/ChromiumBased_history.sqlite")}
|
|
18
|
+
let(:expected_history_sql){'SELECT * FROM urls ORDER BY last_visit_time DESC;'}
|
|
19
|
+
|
|
20
|
+
describe Browser::Chrome::DEFAULT_PROFILE_NAME do
|
|
21
|
+
let(:expected_default_profile_name){'Default'}
|
|
22
|
+
|
|
23
|
+
it "contains the correct default profile name" do
|
|
24
|
+
expect(Browser::Chrome::DEFAULT_PROFILE_NAME).to eq(expected_default_profile_name)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "class methods" do
|
|
29
|
+
subject{Browser::Chrome}
|
|
30
|
+
|
|
31
|
+
describe '.bookmarks_location' do
|
|
32
|
+
let(:expected_bookmarks_location){File.expand_path('~/Library/Application Support/Google/Chrome/Default/Bookmarks')}
|
|
33
|
+
|
|
34
|
+
it "contains the correct bookmarks location" do
|
|
35
|
+
expect(subject.bookmarks_location).to eq(expected_bookmarks_location)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe '.history_location' do
|
|
40
|
+
let(:expected_history_location){File.expand_path('~/Library/Application Support/Google/Chrome/Default/History')}
|
|
41
|
+
|
|
42
|
+
it "contains the correct history location" do
|
|
43
|
+
expect(subject.history_location).to eq(expected_history_location)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe ".bookmarks_sql" do
|
|
48
|
+
it "returns the bookmarks sql" do
|
|
49
|
+
expect(subject.send(:bookmarks_sql)).to be_nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe ".history_sql" do
|
|
54
|
+
it "returns the history sql" do
|
|
55
|
+
expect(subject.send(:history_sql)).to eq(expected_history_sql)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context "instance methods" do
|
|
61
|
+
subject{Browser::Chrome.new(bookmarks_location: bookmarks_fixtures_location, history_location: history_fixtures_location)}
|
|
62
|
+
|
|
63
|
+
let(:browser_name){'Chrome'}
|
|
64
|
+
let(:default_profile_name){'Default'}
|
|
65
|
+
let(:expected_history) do
|
|
66
|
+
[
|
|
67
|
+
{'id' => 1, 'url' => 'https://www.chromium.org/chromium-projects/', 'title' => 'Home', 'visit_count' => 3, 'typed_count' => 1, 'last_visit_time' => 13403232000000000, 'hidden' => 0},
|
|
68
|
+
{'id' => 2, 'url' => 'chrome://welcome/', 'title' => 'Welcome', 'visit_count' => 1, 'typed_count' => 0, 'last_visit_time' => 13403231000000000, 'hidden' => 0},
|
|
69
|
+
]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "#initialize" do
|
|
73
|
+
it "returns an instance of Browser" do
|
|
74
|
+
expect(subject).to be_a(Browser::Chrome)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "assigns @bookmarks_location" do
|
|
78
|
+
expect(subject.instance_variable_get(:@bookmarks_location)).to eq(bookmarks_fixtures_location)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "assigns @history_location" do
|
|
82
|
+
expect(subject.instance_variable_get(:@history_location)).to eq(history_fixtures_location)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "takes the default profile name when none is given" do
|
|
86
|
+
expect(subject.profile_name).to eq(default_profile_name)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe "#name" do
|
|
91
|
+
it "returns name" do
|
|
92
|
+
expect(subject.name).to eq(browser_name)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
let(:expected_bookmarks) do
|
|
97
|
+
[
|
|
98
|
+
{title: 'Home', url: 'https://www.chromium.org/chromium-projects/', folder: 'Bookmarks Bar'},
|
|
99
|
+
]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe "#bookmarks" do
|
|
103
|
+
it "returns an instance of Browser::Bookmarks" do
|
|
104
|
+
expect(subject.bookmarks).to be_a(Browser::Bookmarks)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "returns the bookmarks" do
|
|
108
|
+
expect(subject.bookmarks.to_objects).to eq(expected_bookmarks)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "#history" do
|
|
113
|
+
it "returns an instance of Browser::History" do
|
|
114
|
+
expect(subject.history).to be_a(Browser::History)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "returns the history" do
|
|
118
|
+
expect(subject.history.to_json).to eq(expected_history.to_json)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe "#readable?" do
|
|
123
|
+
it "is true when the data is there" do
|
|
124
|
+
expect(subject.bookmarks.readable?).to be(true)
|
|
125
|
+
expect(subject.history.readable?).to be(true)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
context "WHEN the data is not there" do
|
|
130
|
+
subject{Browser::Chrome.new(bookmarks_location: '/nonexistent/file', history_location: '/nonexistent/file')}
|
|
131
|
+
|
|
132
|
+
it "is not readable" do
|
|
133
|
+
expect(subject.bookmarks.readable?).to be(false)
|
|
134
|
+
expect(subject.history.readable?).to be(false)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "raises Browser::Unreadable" do
|
|
138
|
+
expect{subject.bookmarks.to_json}.to raise_error(Browser::Unreadable)
|
|
139
|
+
expect{subject.history.to_json}.to raise_error(Browser::Unreadable)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|