runoff 0.3.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +18 -17
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +41 -40
- data/Rakefile +7 -7
- data/bin/runoff +58 -34
- data/lib/runoff/commands/all.rb +22 -36
- data/lib/runoff/commands/command.rb +18 -84
- data/lib/runoff/commands/some.rb +38 -0
- data/lib/runoff/file_writer.rb +84 -53
- data/lib/runoff/location.rb +118 -79
- data/lib/runoff/skype_data_format.rb +128 -104
- data/lib/runoff/version.rb +3 -3
- data/lib/runoff.rb +7 -10
- data/runoff.gemspec +27 -26
- data/test/skype_data_format_test.rb +57 -70
- metadata +29 -28
- data/lib/runoff/commands/chat.rb +0 -37
- data/lib/runoff/composition.rb +0 -105
- data/test/all_test.rb +0 -37
- data/test/chat_test.rb +0 -11
- data/test/command_test.rb +0 -41
- data/test/composition_test.rb +0 -58
- data/test/file_writer_test.rb +0 -90
- data/test/location_test.rb +0 -29
data/lib/runoff/location.rb
CHANGED
@@ -1,79 +1,118 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
# Public:
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# # =>
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# Returns a
|
70
|
-
def self.
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Runoff
|
4
|
+
# Contains class methods for finding out the appropriate file paths.
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# Location::default_skype_data_location skype_username
|
9
|
+
# # => /home/user/.Skype/skype_username/main.db
|
10
|
+
class Location
|
11
|
+
# Public: Gets a path to the Skype's main.db file.
|
12
|
+
#
|
13
|
+
# username - A String containing Skype username
|
14
|
+
# options - A hash containing command-line options passed to the command.
|
15
|
+
# If the username is empty, then the hash must contain :from key.
|
16
|
+
#
|
17
|
+
# Examples
|
18
|
+
#
|
19
|
+
# get_database_path('john_doe', {})
|
20
|
+
# # => Path to the default Skype database location depending on the operating system.
|
21
|
+
#
|
22
|
+
# get_database_path('', { from: '~/Desktop/main.db' })
|
23
|
+
# # => '~/Desktop/main.db'
|
24
|
+
#
|
25
|
+
# Returns a String
|
26
|
+
def self.get_database_path(username, options)
|
27
|
+
if options.from
|
28
|
+
options.from
|
29
|
+
else
|
30
|
+
self.default_skype_data_location username
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public: Composes the default Skype database location depending on the operating system.
|
35
|
+
#
|
36
|
+
# skype_username - A String that contains a username of the Skype account,
|
37
|
+
# which database we want to access.
|
38
|
+
#
|
39
|
+
# Examples
|
40
|
+
#
|
41
|
+
# On Linux:
|
42
|
+
# default_skype_data_location skype_username
|
43
|
+
# # => /home/user/.Skype/skype_username/mai.db
|
44
|
+
#
|
45
|
+
# On Windows:
|
46
|
+
# default_skype_data_location skype_username
|
47
|
+
# # => /Users/user/AppData/Roaming/Skype/skype_username/main.db
|
48
|
+
#
|
49
|
+
# Returns a String that contains the path to the Skype database file.
|
50
|
+
def self.default_skype_data_location(skype_username)
|
51
|
+
case RbConfig::CONFIG['host_os']
|
52
|
+
when /mingw/
|
53
|
+
if File.exist?("#{ENV['APPDATA']}\\Skype")
|
54
|
+
format_windows_path "#{ENV['APPDATA']}\\Skype\\#{skype_username}\\main.db"
|
55
|
+
else
|
56
|
+
format_windows_path self.get_default_skype_data_location_on_windows_8(skype_username)
|
57
|
+
end
|
58
|
+
when /linux/
|
59
|
+
"#{ENV['HOME']}/.Skype/#{skype_username}/main.db"
|
60
|
+
else
|
61
|
+
"#{ENV['HOME']}/Library/Application Support/Skype/#{skype_username}/main.db"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Public: Composes a path where the exported files must be saved.
|
66
|
+
#
|
67
|
+
# options - an object with command line options passed to the runoff executable.
|
68
|
+
#
|
69
|
+
# Returns a string with a directory path.
|
70
|
+
def self.get_export_path(options)
|
71
|
+
path = options.destination || "#{ENV['HOME']}"
|
72
|
+
path = "#{path}/skype_chat_history"
|
73
|
+
|
74
|
+
unless File.exist?(path)
|
75
|
+
FileUtils::mkdir_p path
|
76
|
+
end
|
77
|
+
|
78
|
+
path
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# Internal: Replaces backslashes with forward slashes and removes drive letter.
|
84
|
+
#
|
85
|
+
# path - String containing a directory path.
|
86
|
+
#
|
87
|
+
# Examples
|
88
|
+
#
|
89
|
+
# format_windows_path 'C:\Users\username\AppData\Roaming\Skype\skype_username\main.db'
|
90
|
+
# # => /Users/username/AppData/ROaming/Skype/skype_username/main.db
|
91
|
+
#
|
92
|
+
# Returns a String with modified directory path.
|
93
|
+
def self.format_windows_path(path)
|
94
|
+
path = path.gsub(/\\/, '/')
|
95
|
+
path.gsub(/^[a-zA-Z]:/, '')
|
96
|
+
end
|
97
|
+
|
98
|
+
# Internal: Composes the default Skype database location for the Windows 8 operating system.
|
99
|
+
#
|
100
|
+
# skype_username - A String that contains a username of the Skype account,
|
101
|
+
# which database we want to access.
|
102
|
+
#
|
103
|
+
# Examples
|
104
|
+
#
|
105
|
+
# get_default_skype_data_location_on_windows_8 skype_username
|
106
|
+
# # => C:/Users/user/AppData/Local/Packages/Microsoft.SkypeApp_sakjhds8asd/LocalState/skype_username/main.db
|
107
|
+
#
|
108
|
+
# Returns a String that contains the path to the Skype database file.
|
109
|
+
def self.get_default_skype_data_location_on_windows_8(skype_username)
|
110
|
+
location = "#{ENV['HOME']}/AppData/Local/Packages"
|
111
|
+
skype_folder = Dir["#{location}/Microsoft.SkypeApp*"].first
|
112
|
+
|
113
|
+
raise IOError.new "The default Skype directory doesn't exist." unless skype_folder
|
114
|
+
|
115
|
+
"#{skype_folder}/LocalState/#{skype_username}/main.db"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -1,104 +1,128 @@
|
|
1
|
-
module Runoff
|
2
|
-
#
|
3
|
-
class SkypeDataFormat
|
4
|
-
#Public:
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
# # =>
|
97
|
-
#
|
98
|
-
# Returns a string
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
1
|
+
module Runoff
|
2
|
+
# Defines methods to hide the specific format that is used in the Skype database.
|
3
|
+
class SkypeDataFormat
|
4
|
+
# Public: Defines what kind of information can be queried from the database.
|
5
|
+
#
|
6
|
+
# Example
|
7
|
+
#
|
8
|
+
# get_schema do |table, columns|
|
9
|
+
# # SELSECT *columns FROM table
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# get_schema
|
13
|
+
# # => { table: :Messages, columns: [:chatname, :timestamp, :from_dispname, :body_xml] }
|
14
|
+
#
|
15
|
+
# Returns a hash with keys "table" and "columns" if no block is given.
|
16
|
+
def get_schema
|
17
|
+
if block_given?
|
18
|
+
yield :Messages, [:chatname, :timestamp, :from_dispname, :body_xml]
|
19
|
+
else
|
20
|
+
return {
|
21
|
+
table: :Messages,
|
22
|
+
columns: [:chatname, :timestamp, :from_dispname, :body_xml]
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Public: Provides a filename and the data that should be written to the file.
|
28
|
+
#
|
29
|
+
# fields - an array representing a single entry in the database.
|
30
|
+
#
|
31
|
+
# Examples
|
32
|
+
#
|
33
|
+
# build_entry {
|
34
|
+
# chatname: "#john/$doe;1243435",
|
35
|
+
# from_dispname: "John",
|
36
|
+
# body_xml: "Lorem ipsum",
|
37
|
+
# timestamp: 12435463
|
38
|
+
# } # => { filename: john-doe.txt, content: "[2013-12-27 12:23:43] John: Lorem ipsum" }
|
39
|
+
#
|
40
|
+
# Returns a hash with "filename" and "content" keys.
|
41
|
+
def build_entry(fields)
|
42
|
+
chatname = fields[:chatname]
|
43
|
+
username = fields[:from_dispname]
|
44
|
+
message = parse_xml fields[:body_xml]
|
45
|
+
datetime = Time.at(fields[:timestamp]).strftime "%Y-%m-%d %H:%M:%S"
|
46
|
+
|
47
|
+
{
|
48
|
+
filename: get_filename(chatname),
|
49
|
+
content: "[#{datetime}] #{username}: #{message}\n"
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
# Public: Parse a into a human readable format.
|
54
|
+
#
|
55
|
+
# chatname - a string that must be normalized.
|
56
|
+
#
|
57
|
+
# Examples
|
58
|
+
#
|
59
|
+
# normalize "#john/$doe;2354657"
|
60
|
+
# # => john-doe
|
61
|
+
#
|
62
|
+
# Returns a string without unnecessary characters.
|
63
|
+
def normalize(chatname)
|
64
|
+
pattern = /^#(.+)\/\$(.+)?;.*$/
|
65
|
+
initiator, respondent = chatname.match(pattern).captures
|
66
|
+
|
67
|
+
"#{initiator}-#{respondent}".gsub(/(^-+|-+$)/, '')
|
68
|
+
end
|
69
|
+
|
70
|
+
# Public: Converts a string that is similar to the chat title stored
|
71
|
+
# in the Skype database.
|
72
|
+
#
|
73
|
+
# dispname - a string that is displayed to the user as a chat title.
|
74
|
+
#
|
75
|
+
# Examples
|
76
|
+
#
|
77
|
+
# denormalize "john-doe"
|
78
|
+
# # => "#john/$doe;"
|
79
|
+
#
|
80
|
+
# Returns a string that can be used to query Skype database.
|
81
|
+
def denormalize(dispname)
|
82
|
+
parts = dispname.split '-'
|
83
|
+
|
84
|
+
parts.count == 2 ? "##{parts[0]}/$#{parts[1]};" : "##{parts[0]}/$;"
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# Internal: Parses a string into a valid file name.
|
90
|
+
#
|
91
|
+
# chatname - a string that must be converted into a valid filename.
|
92
|
+
#
|
93
|
+
# Examples
|
94
|
+
#
|
95
|
+
# get_filename "#john/$doe;2354657"
|
96
|
+
# # => john-doe.txt
|
97
|
+
#
|
98
|
+
# Returns a string that can be used as a file name.
|
99
|
+
def get_filename(chatname)
|
100
|
+
normalize(chatname) + ".txt"
|
101
|
+
end
|
102
|
+
|
103
|
+
# Internal: removes unnecessary XML code from the message.
|
104
|
+
#
|
105
|
+
# message - a string to parse
|
106
|
+
#
|
107
|
+
# Examples
|
108
|
+
#
|
109
|
+
# parse_xml "<ss type="smile">:)</ss>"
|
110
|
+
# # => ":)"
|
111
|
+
#
|
112
|
+
# Returns an XML-free string.
|
113
|
+
def parse_xml(message)
|
114
|
+
if message
|
115
|
+
message = message.gsub /<ss type=".*">/, ''
|
116
|
+
message = message.gsub /<\/ss>/, ''
|
117
|
+
message = message.gsub /<a href=".*">/, ''
|
118
|
+
message = message.gsub /<\/a>/, ''
|
119
|
+
message = message.gsub /'/, "'"
|
120
|
+
message = message.gsub /</, '<'
|
121
|
+
message = message.gsub />/, '>'
|
122
|
+
message = message.gsub /"/, '"'
|
123
|
+
end
|
124
|
+
|
125
|
+
message
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/runoff/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Runoff
|
2
|
-
VERSION = '0.
|
3
|
-
end
|
1
|
+
module Runoff
|
2
|
+
VERSION = '1.0.0'
|
3
|
+
end
|
data/lib/runoff.rb
CHANGED
@@ -1,10 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require "runoff/commands/command"
|
9
|
-
require "runoff/commands/all"
|
10
|
-
require "runoff/commands/chat"
|
1
|
+
require 'runoff/version'
|
2
|
+
require 'runoff/location'
|
3
|
+
require 'runoff/skype_data_format'
|
4
|
+
require 'runoff/file_writer'
|
5
|
+
require 'runoff/commands/command'
|
6
|
+
require 'runoff/commands/all'
|
7
|
+
require 'runoff/commands/some'
|
data/runoff.gemspec
CHANGED
@@ -1,26 +1,27 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
|
5
|
-
require 'runoff/version'
|
6
|
-
|
7
|
-
Gem::Specification.new do |gem|
|
8
|
-
gem.name = "runoff"
|
9
|
-
gem.version = Runoff::VERSION
|
10
|
-
gem.authors = ["Aigars Dzerviniks"]
|
11
|
-
gem.email = ["dzerviniks.aigars@outlook.com"]
|
12
|
-
gem.description = %q{runoff provides functionality to export all the Skype chat history or only specified chats from the Skype SQLite database file to text files}
|
13
|
-
gem.summary = %q{Tool to export Skype chat history from the SQLite database to text files}
|
14
|
-
gem.homepage = 'https://github.com/
|
15
|
-
gem.license = 'MIT'
|
16
|
-
|
17
|
-
gem.files = `git ls-files`.split($/)
|
18
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
-
gem.require_paths = ["lib"]
|
21
|
-
|
22
|
-
gem.add_dependency 'commander'
|
23
|
-
gem.add_dependency 'sequel'
|
24
|
-
gem.add_dependency 'rubyzip'
|
25
|
-
gem.add_dependency 'sqlite3'
|
26
|
-
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'runoff/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |gem|
|
8
|
+
gem.name = "runoff"
|
9
|
+
gem.version = Runoff::VERSION
|
10
|
+
gem.authors = ["Aigars Dzerviniks"]
|
11
|
+
gem.email = ["dzerviniks.aigars@outlook.com"]
|
12
|
+
gem.description = %q{runoff provides functionality to export all the Skype chat history or only specified chats from the Skype SQLite database file to text files}
|
13
|
+
gem.summary = %q{Tool to export Skype chat history from the SQLite database to text files}
|
14
|
+
gem.homepage = 'https://github.com/aigarsdz/runoff'
|
15
|
+
gem.license = 'MIT'
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.split($/)
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.require_paths = ["lib"]
|
21
|
+
|
22
|
+
gem.add_dependency 'commander'
|
23
|
+
gem.add_dependency 'sequel'
|
24
|
+
gem.add_dependency 'rubyzip'
|
25
|
+
gem.add_dependency 'sqlite3'
|
26
|
+
gem.add_dependency 'colorize'
|
27
|
+
end
|
@@ -1,71 +1,58 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
def test_must_return_a_string_without_skype_emotion_xml_tags
|
59
|
-
string = 'Some text <ss type="laugh">:D</ss>'
|
60
|
-
clean_string = @format.send :parse_body_xml, string
|
61
|
-
|
62
|
-
assert_equal 'Some text :D', clean_string
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_must_remove_all_starting_and_ending_dashes_from_a_string
|
66
|
-
string = '---example--'
|
67
|
-
valid_name = @format.send :trim_dashes, string
|
68
|
-
|
69
|
-
assert_equal 'example', valid_name
|
70
|
-
end
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'runoff'
|
3
|
+
|
4
|
+
describe Runoff::SkypeDataFormat do
|
5
|
+
before do
|
6
|
+
@format = Runoff::SkypeDataFormat.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "must return a schema of the necessary data" do
|
10
|
+
expected = { table: :Messages, columns: [:chatname, :timestamp, :from_dispname, :body_xml] }
|
11
|
+
|
12
|
+
@format.get_schema.must_equal expected
|
13
|
+
end
|
14
|
+
|
15
|
+
it "must yield a schema of the necessary data to a block" do
|
16
|
+
@format.get_schema do |table, columns|
|
17
|
+
table.must_equal :Messages
|
18
|
+
columns.must_equal [:chatname, :timestamp, :from_dispname, :body_xml]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "must return a hash with 'filename' and 'content' keys based on the input data" do
|
23
|
+
fields = {
|
24
|
+
chatname: "#john/$doe;1243435",
|
25
|
+
from_dispname: "John",
|
26
|
+
body_xml: "Lorem ipsum",
|
27
|
+
timestamp: 1387756800
|
28
|
+
}
|
29
|
+
|
30
|
+
expected = { filename: "john-doe.txt", content: "[2013-12-23 02:00:00] John: Lorem ipsum\n" }
|
31
|
+
|
32
|
+
@format.build_entry(fields).must_equal expected
|
33
|
+
end
|
34
|
+
|
35
|
+
it "must normalize a Skype specific chat title into a human readable string" do
|
36
|
+
@format.normalize('#john/$doe;2354657').must_equal 'john-doe'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "must normalize a Skype specific chat title into a human readable string even in case of invalid title" do
|
40
|
+
@format.normalize('#john/$;2354657').must_equal 'john'
|
41
|
+
end
|
42
|
+
|
43
|
+
it "must parse a Skype specific chat title into a valid file name" do
|
44
|
+
@format.send(:get_filename, '#john/$doe;2354657').must_equal 'john-doe.txt'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "must parse a Skype specific chat title into a valid file name even in case of invalid title" do
|
48
|
+
@format.send(:get_filename, '#john/$;2354657').must_equal 'john.txt'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "must denormalize a human readable chat title into a string that can be used in a database query" do
|
52
|
+
@format.denormalize('john-doe').must_equal '#john/$doe;'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "must denormalize a human readable, invalid chat title into a string that can be used in a database query" do
|
56
|
+
@format.denormalize('john').must_equal '#john/$;'
|
57
|
+
end
|
71
58
|
end
|