ipreader 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|