ipreader 0.0.1
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.
- data/.gitignore +8 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +31 -0
- data/README +0 -0
- data/Rakefile +2 -0
- data/bin/ext_sms +12 -0
- data/bin/ext_sms.rb +49 -0
- data/ipreader/database_utils.rb +82 -0
- data/ipreader/display.rb +42 -0
- data/ipreader/init.rb +0 -0
- data/ipreader/templates/sms.csv.haml +3 -0
- data/ipreader/templates/sms.html.haml +10 -0
- data/ipreader/templates/sms.missing.haml +1 -0
- data/ipreader/templates/sms.xml.haml +6 -0
- data/ipreader/version.rb +7 -0
- data/ipreader.gemspec +22 -0
- data/ipreader.rb +49 -0
- data/test/test_database_utils.rb +46 -0
- data/test/test_database_utils2.rb +98 -0
- data/test/test_display.rb +66 -0
- data/test/test_helper.rb +33 -0
- data/test/test_unit_extensions.rb +20 -0
- metadata +73 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
group :test do
|
4
|
+
gem "fakefs", :git => "git://github.com/vertiginous/fakefs.git"
|
5
|
+
gem "mocha"
|
6
|
+
end
|
7
|
+
|
8
|
+
gem "haml", ">=3.0.24"
|
9
|
+
gem "sqlite3-ruby", :require => "sqlite3"
|
10
|
+
|
11
|
+
#group :development do
|
12
|
+
#end
|
13
|
+
|
14
|
+
# Specify your gem's dependencies in ipreader.gemspec
|
15
|
+
gemspec
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/vertiginous/fakefs.git
|
3
|
+
revision: 7a35534e02128c95650d59fd95d34ef7cb04313b
|
4
|
+
specs:
|
5
|
+
fakefs (0.3.1)
|
6
|
+
|
7
|
+
PATH
|
8
|
+
remote: .
|
9
|
+
specs:
|
10
|
+
ipreader (0.0.1)
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: http://rubygems.org/
|
14
|
+
specs:
|
15
|
+
haml (3.0.25)
|
16
|
+
mocha (0.9.9)
|
17
|
+
rake
|
18
|
+
rake (0.8.7)
|
19
|
+
sqlite3 (1.3.3-x86-mingw32)
|
20
|
+
sqlite3-ruby (1.3.3)
|
21
|
+
sqlite3 (>= 1.3.3)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
x86-mingw32
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
fakefs!
|
28
|
+
haml (>= 3.0.24)
|
29
|
+
ipreader!
|
30
|
+
mocha
|
31
|
+
sqlite3-ruby
|
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
data/bin/ext_sms
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
##!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
4
|
+
|
5
|
+
dir_name = "/users/{user}/AppData/Roaming/Apple\ Computer/MobileSync/Backup/{directory name}"
|
6
|
+
output_format = "html"
|
7
|
+
|
8
|
+
dir_name = ARGV[0] if ARGV.length == 1
|
9
|
+
output_format = ARGV[1] if ARGV.length == 2
|
10
|
+
|
11
|
+
require "ipreader"
|
12
|
+
Ipreader.Controller.read_backups(dir_name, output_format)
|
data/bin/ext_sms.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#$:.unshift File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require_relative "../ipreader"
|
7
|
+
|
8
|
+
OptionParser.accept(Date, /(\d+)-(\d+)-(\d+)/) do |d, mon, day, year|
|
9
|
+
Date.new( year.to_i, mon.to_i, day.to_i )
|
10
|
+
end
|
11
|
+
|
12
|
+
opts = OptionParser.new
|
13
|
+
|
14
|
+
opts.banner = "Usage: ext_sms [ options ]"
|
15
|
+
|
16
|
+
opts.on("-h", "--help", "-?", "show this message") do
|
17
|
+
puts opts
|
18
|
+
exit
|
19
|
+
end
|
20
|
+
|
21
|
+
format = "html"
|
22
|
+
opts.on("-fo", "--format FORMAT", String, "Output format, one of [html, csv, xml]") do |fmt|
|
23
|
+
format = fmt
|
24
|
+
end
|
25
|
+
|
26
|
+
backup_path = ""
|
27
|
+
opts.on("-p", "--path PATHNAME", "Path to backup directory") do |pth|
|
28
|
+
backup_path = pth
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO add date filters
|
32
|
+
filters = {}
|
33
|
+
opts.on("-fi", "--filters 'COLUMN_NAME:value'", String, "Filter to apply, columns [address:value[, text:value]]") do |fltrs|
|
34
|
+
fltrs.scan(/(\w+):\s*(\w+)/) do |name, value|
|
35
|
+
filters[name] = "%" + value + "%"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
ARGV << "-h" if ARGV.empty?
|
41
|
+
opts.parse!(ARGV)
|
42
|
+
backup_reader = Ipreader::Controller.new(backup_path, format, filters)
|
43
|
+
puts backup_reader.start
|
44
|
+
rescue OptionParser::ParseError => e
|
45
|
+
STDERR.puts e.message, "\n", opts
|
46
|
+
exit(-1)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'sqlite3'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Ipreader
|
5
|
+
|
6
|
+
module Database
|
7
|
+
|
8
|
+
module Utils
|
9
|
+
|
10
|
+
def is_sqlite3?(full_name)
|
11
|
+
return false if full_name.nil?
|
12
|
+
file_data = File.open(full_name, "r")
|
13
|
+
file_header = file_data.gets
|
14
|
+
file_header =~ /^SQLite format 3/
|
15
|
+
end
|
16
|
+
|
17
|
+
def sms_db?(full_name)
|
18
|
+
return false if full_name.nil?
|
19
|
+
SQLite3::Database.new(full_name) do |db|
|
20
|
+
begin
|
21
|
+
if db.execute("SELECT count(*) FROM SQLITE_MASTER WHERE type='table' AND name='message'").flatten.first > 0
|
22
|
+
return true
|
23
|
+
else
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
rescue SQLite3::SQLException, SQLite3::IOException, NilClass => e
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def read_sms_table(full_name, filters = {} )
|
33
|
+
|
34
|
+
sms_list = Array.new
|
35
|
+
SQLite3::Database.new(full_name) do |db|
|
36
|
+
|
37
|
+
message_table_columns = db.execute2("SELECT * FROM message LIMIT 0").flatten
|
38
|
+
column_keys = filters.keys.collect { |k| k.to_s }
|
39
|
+
non_matched_columns = column_keys - message_table_columns
|
40
|
+
if non_matched_columns.length > 0
|
41
|
+
raise ArgumentError, "can't find column [#{non_matched_columns}] in messages"
|
42
|
+
exit
|
43
|
+
else
|
44
|
+
optional_filters = ""
|
45
|
+
filters.keys.each do |filter|
|
46
|
+
optional_filters += " AND #{filter} LIKE :#{filter}"
|
47
|
+
end
|
48
|
+
sql = "SELECT rowid, date(date,'unixepoch'), address, text, flags, time(date,'unixepoch')"
|
49
|
+
sql += " FROM message"
|
50
|
+
sql += " WHERE text is not null #{optional_filters}"
|
51
|
+
sql += " ORDER BY address AND date ASC"
|
52
|
+
|
53
|
+
# puts "sql=#{sql}"
|
54
|
+
# sql += " LIMIT 5"
|
55
|
+
|
56
|
+
begin
|
57
|
+
db.execute(sql, filters) do |row|
|
58
|
+
direction = case row[4]
|
59
|
+
when 2 then "to"
|
60
|
+
when 3 then "from"
|
61
|
+
else "??"
|
62
|
+
end
|
63
|
+
# TODO connascence of position
|
64
|
+
row_hash = { :rowid => row[0],
|
65
|
+
:on_date => row[1],
|
66
|
+
:at_time => row[5],
|
67
|
+
:address => row[2],
|
68
|
+
:direction => direction,
|
69
|
+
:text => row[3]
|
70
|
+
}
|
71
|
+
sms_list << row_hash
|
72
|
+
end
|
73
|
+
rescue SQLite3::Exception => e
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
return sms_list
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/ipreader/display.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Ipreader
|
2
|
+
|
3
|
+
module Display
|
4
|
+
|
5
|
+
# KNOWN_FORMATS = [ "xml", "csv", "html" ]
|
6
|
+
# NO_TEMPLATE = "no template chosen"
|
7
|
+
# TEMPLATE_LOCATION = "templates"
|
8
|
+
|
9
|
+
@missing = ''
|
10
|
+
|
11
|
+
def which_template(format)
|
12
|
+
known_fmt = lambda { |item| KNOWN_FORMATS.include?(item) }
|
13
|
+
case format
|
14
|
+
when known_fmt
|
15
|
+
"#{Ipreader::TEMPLATE_LOCATION}/sms.#{format.strip}.haml"
|
16
|
+
else
|
17
|
+
@missing = format
|
18
|
+
"#{Ipreader::TEMPLATE_LOCATION}/sms.missing.haml"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def template_location(templ)
|
23
|
+
File.join(File.dirname(__FILE__), which_template(templ))
|
24
|
+
end
|
25
|
+
|
26
|
+
def display_sms( template_type = "html" , conversations = nil)
|
27
|
+
temp_loc = template_location(template_type)
|
28
|
+
render_template(File.read(temp_loc), conversations)
|
29
|
+
end
|
30
|
+
|
31
|
+
def render_template( template = nil, conversations = nil )
|
32
|
+
unless template.nil?
|
33
|
+
Haml::Engine.new(template).render( Object.new, :conversations => conversations, :missing => @missing )
|
34
|
+
else
|
35
|
+
Ipreader::NO_TEMPLATE
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
data/ipreader/init.rb
ADDED
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
I'am missing a template for "#{missing}"
|
data/ipreader/version.rb
ADDED
data/ipreader.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.dirname(__FILE__)
|
3
|
+
#$:.push File.join( File.dirname(__FILE__),'ipreader' )
|
4
|
+
require "ipreader/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "ipreader"
|
8
|
+
s.version = Ipreader::Backup::Reader::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ["David Rabbich"]
|
11
|
+
s.email = ["davidrabbich@yahoo.co.uk"]
|
12
|
+
s.homepage = "http://rubygems.org/gems/ipreader"
|
13
|
+
s.summary = %q{ Reads an unencrypted IPhone backup store and queries the sms data within it. }
|
14
|
+
s.description = %q{ Takes as input a directory location of the Apple backup store and interrogates the back up data for SMS data }
|
15
|
+
|
16
|
+
s.rubyforge_project = "ipreader"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
end
|
data/ipreader.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'haml'
|
3
|
+
require 'sqlite3'
|
4
|
+
|
5
|
+
require_relative "ipreader/database_utils"
|
6
|
+
require_relative "ipreader/display"
|
7
|
+
|
8
|
+
module Ipreader
|
9
|
+
|
10
|
+
KNOWN_FORMATS = [ "xml", "csv", "html" ]
|
11
|
+
NO_TEMPLATE = "no template chosen"
|
12
|
+
LIBRARY_LOCATION = "ipreader"
|
13
|
+
TEMPLATE_LOCATION = "templates"
|
14
|
+
|
15
|
+
class Controller
|
16
|
+
|
17
|
+
include Ipreader::Database::Utils
|
18
|
+
include Ipreader::Display
|
19
|
+
|
20
|
+
def initialize(backup_path = nil, format = "html" , filters = {} )
|
21
|
+
@conversations = []
|
22
|
+
@backup_path = backup_path
|
23
|
+
@template_type = format
|
24
|
+
@filters = filters
|
25
|
+
end
|
26
|
+
|
27
|
+
def start
|
28
|
+
read_backups
|
29
|
+
display_sms(@template_type, @conversations.flatten)
|
30
|
+
end
|
31
|
+
|
32
|
+
# control which backup directories to read through
|
33
|
+
# TODO more than one backup directory
|
34
|
+
# TODO more than one database type
|
35
|
+
def read_backups
|
36
|
+
Dir.foreach(@backup_path) do |file_name|
|
37
|
+
full_name = File.join(@backup_path, file_name)
|
38
|
+
unless File.directory?(full_name)
|
39
|
+
if is_sqlite3?(full_name)
|
40
|
+
@conversations << read_sms_table(full_name, @filters) if sms_db?(full_name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
# @conversations
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
require_relative "../ipreader/database_utils"
|
3
|
+
|
4
|
+
require 'fakefs/safe'
|
5
|
+
|
6
|
+
class TestDatabaseUtils < Test::Unit::TestCase
|
7
|
+
|
8
|
+
include FakeFS
|
9
|
+
|
10
|
+
class IpDbUtils
|
11
|
+
include Ipreader::Database::Utils
|
12
|
+
end
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@ipdbutils = IpDbUtils.new
|
16
|
+
FakeFS.activate!
|
17
|
+
FileSystem.clear
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
FakeFS.deactivate!
|
22
|
+
end
|
23
|
+
|
24
|
+
must "is_sqlite3? returns true the given file IS in a Sqlite3 format" do
|
25
|
+
test_db_path = File.join(test_root, "tmp", "sqlite3_valid_fake.sqlite3" )
|
26
|
+
File.open(test_db_path, 'w') { |f| f.write "SQLite format 3" }
|
27
|
+
assert @ipdbutils.is_sqlite3?(test_db_path), "first characters of a valid SQLite3 database should be 'SQLite format 3'"
|
28
|
+
end
|
29
|
+
|
30
|
+
must "is_sqlite3? returns false if the given file is NOT a valid Sqlite3 format" do
|
31
|
+
test_bad_path = File.join(test_root, "tmp", "sqlite3_invalid_fake.MSSQL" )
|
32
|
+
File.open(test_bad_path, 'w') { |f| f.write "SQL Server 2000" }
|
33
|
+
refute @ipdbutils.is_sqlite3?(test_bad_path), "should return false to a non SQLite3 file"
|
34
|
+
end
|
35
|
+
|
36
|
+
must "return false if the SQLite3 file is malformed" do
|
37
|
+
test_malformed_path = File.join(test_root, "tmp", "sqlite3_malformed_fake.sqlite3" )
|
38
|
+
File.open(test_malformed_path, 'w') { |f| f.write "xxxxxxxxxxxxxxSQLite format 3" }
|
39
|
+
refute @ipdbutils.is_sqlite3?(test_malformed_path), "first characters are not a valid SQLite3 database"
|
40
|
+
end
|
41
|
+
|
42
|
+
must "fail gracefully if the given file does not exist" do
|
43
|
+
refute @ipdbutils.is_sqlite3?(nil), "should return false when no file is given"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
require_relative "../ipreader/database_utils"
|
3
|
+
require "sqlite3"
|
4
|
+
|
5
|
+
class TestDatabaseUtils < Test::Unit::TestCase
|
6
|
+
|
7
|
+
SMS_TABLE_CREATE = "CREATE TABLE message (rowid INTEGER, date TEXT, address TEXT, text TEXT, flags INTEGER)"
|
8
|
+
|
9
|
+
class IpDbUtils
|
10
|
+
include Ipreader::Database::Utils
|
11
|
+
end
|
12
|
+
|
13
|
+
def setup
|
14
|
+
@db_name = File.join(File.dirname(__FILE__), "tmp/dummy.sqlite3")
|
15
|
+
file_teardown(@db_name) if File.exists?(@db_name)
|
16
|
+
@ipdbutils = IpDbUtils.new
|
17
|
+
@db = SQLite3::Database.new @db_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
@db.close unless @db.closed?
|
22
|
+
GC.start
|
23
|
+
file_teardown(@db_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def file_teardown(file_name)
|
27
|
+
File.delete(file_name) if File.exists?(file_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
must "recognise an sms backup" do
|
31
|
+
@db.execute SMS_TABLE_CREATE
|
32
|
+
assert @ipdbutils.sms_db?(@db_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
must "recognise when database is not an sms backup" do
|
36
|
+
@db.execute "CREATE TABLE smerf (name VARCHAR(30))"
|
37
|
+
refute @ipdbutils.sms_db?(@db_name)
|
38
|
+
end
|
39
|
+
|
40
|
+
must "fail gracefully if passed a file name that is not a SQLite3 database" do
|
41
|
+
dummy_file = File.join(test_root, "tmp/empty.sqlite3")
|
42
|
+
File.open(dummy_file, "w") { |df| df.puts " " } # "w" truncates existing db contents
|
43
|
+
refute @ipdbutils.sms_db?(dummy_file)
|
44
|
+
end
|
45
|
+
|
46
|
+
must "fail gracefully if passed a nil reference" do
|
47
|
+
refute @ipdbutils.sms_db?(nil)
|
48
|
+
end
|
49
|
+
|
50
|
+
def setup_testdb
|
51
|
+
@db.execute SMS_TABLE_CREATE
|
52
|
+
@test_sms = []
|
53
|
+
(1..4).each do |test_item|
|
54
|
+
insert_sms = "INSERT INTO message (rowid, date, address, text, flags) VALUES( '#{test_item}', '2011-01-31 12:00:00', '+4479867#{test_item}#{test_item}#{test_item}#{test_item}', 'sms text #{test_item}', '2' );"
|
55
|
+
@db.execute(insert_sms)
|
56
|
+
@test_sms << {
|
57
|
+
:rowid => test_item,
|
58
|
+
:on_date => "2011/01/31",
|
59
|
+
:at_time => "12:00:00",
|
60
|
+
:address => "+4479867#{test_item}#{test_item}#{test_item}#{test_item}",
|
61
|
+
:direction => 'to',
|
62
|
+
:text => "sms text #{test_item}"
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
must "return all rows when no filter is applied" do
|
68
|
+
setup_testdb
|
69
|
+
test_result = @ipdbutils.read_sms_table(@db_name)
|
70
|
+
assert_equal test_result, @test_sms
|
71
|
+
assert_equal @test_sms.length, test_result.length
|
72
|
+
end
|
73
|
+
|
74
|
+
must "correctly use the options hash to filter sms data" do
|
75
|
+
setup_testdb
|
76
|
+
result = []
|
77
|
+
result << @test_sms.first
|
78
|
+
options = { :address => "+44798671111" }
|
79
|
+
test_result = @ipdbutils.read_sms_table(@db_name, options)
|
80
|
+
assert_equal test_result, result
|
81
|
+
assert_equal test_result.length, 1
|
82
|
+
end
|
83
|
+
|
84
|
+
must "ignore case when filtering sms data" do
|
85
|
+
setup_testdb
|
86
|
+
options = { :text => "sms text 1" }
|
87
|
+
assert_equal @ipdbutils.read_sms_table(@db_name, options).length, 1
|
88
|
+
options = { :text => "SMS TEXT 1" }
|
89
|
+
assert_equal @ipdbutils.read_sms_table(@db_name, options).length, 1
|
90
|
+
end
|
91
|
+
|
92
|
+
must "ignore surplus options without erroring" do
|
93
|
+
setup_testdb
|
94
|
+
options = { :telephone => "011232131232" }
|
95
|
+
assert_raises(ArgumentError) { @ipdbutils.read_sms_table(@db_name, options) }
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
require_relative "../ipreader/display"
|
3
|
+
|
4
|
+
class TestDisplay < Test::Unit::TestCase
|
5
|
+
|
6
|
+
class IpDisplay
|
7
|
+
include Ipreader::Display
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@display = IpDisplay.new
|
12
|
+
@unknown_fmt = "any-unknown-format"
|
13
|
+
end
|
14
|
+
|
15
|
+
known_template_formats.each do |fmt|
|
16
|
+
must "respond with 'templates/sms.#{fmt}.haml' when display_format gets a known format '#{fmt}'" do
|
17
|
+
assert_equal @display.which_template(fmt), "templates/sms.#{fmt}.haml"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
must "respond with missing template when display_format gets an unknown format of #{@unknown_fmt}" do
|
21
|
+
assert_equal @display.which_template(@unknown_fmt), "templates/sms.missing.haml"
|
22
|
+
end
|
23
|
+
|
24
|
+
must "have an real life template for each of the list of known formats" do
|
25
|
+
known_template_formats.each do |fmt|
|
26
|
+
assert File.exists?(@display.template_location(fmt)), "template #{fmt} does not actually exist"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
must "have a library directory where the library constant defines it" do
|
31
|
+
library_path = File.join(app_root, library_loc)
|
32
|
+
assert File.directory?(library_path), "library #{library_path} does not actually exist"
|
33
|
+
end
|
34
|
+
|
35
|
+
must "have a template directory where the template_path constant defines it" do
|
36
|
+
template_path = File.join(app_root, library_loc, template_loc)
|
37
|
+
assert File.directory?(template_path), "template directory #{template_path} does not actually exist"
|
38
|
+
end
|
39
|
+
|
40
|
+
must "create the correct fully qualified template name" do
|
41
|
+
assert_equal @display.template_location("html"), File.join(templates_path,"sms.html.haml")
|
42
|
+
end
|
43
|
+
|
44
|
+
# def display_sms(template)
|
45
|
+
# temp_loc = template_location(template)
|
46
|
+
# display_template(File.read(temp_loc))
|
47
|
+
# end
|
48
|
+
# must "read from the correct template location" do
|
49
|
+
# mock_template = flexmock(File).should_receive(:read).with("html").and_return(:ok)
|
50
|
+
# assert_equal :ok, @display.display_sms("html")
|
51
|
+
# end
|
52
|
+
|
53
|
+
# def render_template( template = nil )
|
54
|
+
# unless template.nil?
|
55
|
+
# Haml::Engine.new(template).render( Object.new, :conversations => @conversations, :missing => @missing )
|
56
|
+
# else
|
57
|
+
# NO_TEMPLATE
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
must "return a no template message if no template is passed" do
|
61
|
+
assert_equal @display.render_template(nil), no_template
|
62
|
+
end
|
63
|
+
# must "render the and html template correctly" do
|
64
|
+
# end
|
65
|
+
|
66
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "minitest/unit"
|
2
|
+
require_relative "test_unit_extensions"
|
3
|
+
require "flexmock/test_unit"
|
4
|
+
require_relative "../ipreader"
|
5
|
+
|
6
|
+
|
7
|
+
def template_loc
|
8
|
+
Ipreader::TEMPLATE_LOCATION
|
9
|
+
end
|
10
|
+
|
11
|
+
def library_loc
|
12
|
+
Ipreader::LIBRARY_LOCATION
|
13
|
+
end
|
14
|
+
|
15
|
+
def no_template
|
16
|
+
Ipreader::NO_TEMPLATE
|
17
|
+
end
|
18
|
+
|
19
|
+
def known_template_formats
|
20
|
+
Ipreader::KNOWN_FORMATS
|
21
|
+
end
|
22
|
+
|
23
|
+
def app_root
|
24
|
+
File.expand_path(File.join(File.dirname(__FILE__),".."))
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_root
|
28
|
+
File.join(app_root,"test")
|
29
|
+
end
|
30
|
+
|
31
|
+
def templates_path
|
32
|
+
File.join(app_root, library_loc, template_loc)
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MiniTest
|
2
|
+
class Unit
|
3
|
+
# Used to fix a minor minitest/unit incompatibility in flexmock
|
4
|
+
AssertionFailedError = Class.new(StandardError)
|
5
|
+
class TestCase
|
6
|
+
def self.must(name, &block)
|
7
|
+
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
8
|
+
defined = instance_method(test_name) rescue false
|
9
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
10
|
+
if block_given?
|
11
|
+
define_method(test_name, &block)
|
12
|
+
else
|
13
|
+
define_method(test_name) do
|
14
|
+
flunk "No implementation provided for #{name}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ipreader
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease: !!null
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Rabbich
|
9
|
+
autorequire: !!null
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-03-15 00:00:00.000000000 +00:00
|
13
|
+
default_executable: !!null
|
14
|
+
dependencies: []
|
15
|
+
description: ! ' Takes as input a directory location of the Apple backup store and
|
16
|
+
interrogates the back up data for SMS data '
|
17
|
+
email:
|
18
|
+
- davidrabbich@yahoo.co.uk
|
19
|
+
executables:
|
20
|
+
- ext_sms
|
21
|
+
- ext_sms.rb
|
22
|
+
extensions: []
|
23
|
+
extra_rdoc_files: []
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- Gemfile
|
27
|
+
- Gemfile.lock
|
28
|
+
- README
|
29
|
+
- Rakefile
|
30
|
+
- bin/ext_sms
|
31
|
+
- bin/ext_sms.rb
|
32
|
+
- ipreader.gemspec
|
33
|
+
- ipreader.rb
|
34
|
+
- ipreader/database_utils.rb
|
35
|
+
- ipreader/display.rb
|
36
|
+
- ipreader/init.rb
|
37
|
+
- ipreader/templates/sms.csv.haml
|
38
|
+
- ipreader/templates/sms.html.haml
|
39
|
+
- ipreader/templates/sms.missing.haml
|
40
|
+
- ipreader/templates/sms.xml.haml
|
41
|
+
- ipreader/version.rb
|
42
|
+
- test/test_database_utils.rb
|
43
|
+
- test/test_database_utils2.rb
|
44
|
+
- test/test_display.rb
|
45
|
+
- test/test_helper.rb
|
46
|
+
- test/test_unit_extensions.rb
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://rubygems.org/gems/ipreader
|
49
|
+
licenses: []
|
50
|
+
post_install_message: !!null
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project: ipreader
|
68
|
+
rubygems_version: 1.5.0
|
69
|
+
signing_key: !!null
|
70
|
+
specification_version: 3
|
71
|
+
summary: Reads an unencrypted IPhone backup store and queries the sms data within
|
72
|
+
it.
|
73
|
+
test_files: []
|