nilclass-maildir 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +113 -0
- data/Rakefile +32 -0
- data/VERSION +1 -0
- data/benchmarks/runner +30 -0
- data/lib/maildir.rb +115 -0
- data/lib/maildir/keywords.rb +111 -0
- data/lib/maildir/message.rb +241 -0
- data/lib/maildir/serializer/base.rb +20 -0
- data/lib/maildir/serializer/json.rb +13 -0
- data/lib/maildir/serializer/mail.rb +13 -0
- data/lib/maildir/serializer/marshal.rb +12 -0
- data/lib/maildir/serializer/yaml.rb +13 -0
- data/lib/maildir/subdirs.rb +70 -0
- data/lib/maildir/unique_name.rb +72 -0
- data/maildir.gemspec +81 -0
- data/test/test_helper.rb +38 -0
- data/test/test_keywords.rb +16 -0
- data/test/test_maildir.rb +73 -0
- data/test/test_message.rb +226 -0
- data/test/test_serializers.rb +37 -0
- data/test/test_subdirs.rb +46 -0
- data/test/test_unique_name.rb +43 -0
- metadata +125 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Maildir::Serializer
|
2
|
+
# The Maildir::Serializer::Base class reads & writes data to disk as a
|
3
|
+
# string. Other serializers (e.g. Maildir::Serializer::Mail) can extend this
|
4
|
+
# class to do some pre- and post-processing of the string.
|
5
|
+
#
|
6
|
+
# The Serializer API has two methods:
|
7
|
+
# load(path) # => returns data
|
8
|
+
# dump(data, path) # => returns number of bytes written
|
9
|
+
class Base
|
10
|
+
# Reads the file at path. Returns the contents of path.
|
11
|
+
def load(path)
|
12
|
+
File.read(path)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Writes data to path. Returns number of bytes written.
|
16
|
+
def dump(data, path)
|
17
|
+
File.open(path, "w") {|file| file.write(data)}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'json'
|
2
|
+
# Serialize messages as JSON
|
3
|
+
class Maildir::Serializer::JSON < Maildir::Serializer::Base
|
4
|
+
# Read data from path and parse it as JSON.
|
5
|
+
def load(path)
|
6
|
+
::JSON.load(super(path))
|
7
|
+
end
|
8
|
+
|
9
|
+
# Dump data as JSON and writes it to path.
|
10
|
+
def dump(data, path)
|
11
|
+
super(data.to_json, path)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'mail'
|
2
|
+
# Serialize messages as a ruby Mail object
|
3
|
+
class Maildir::Serializer::Mail < Maildir::Serializer::Base
|
4
|
+
# Build a new Mail object from the data at path.
|
5
|
+
def load(path)
|
6
|
+
::Mail.new(super(path))
|
7
|
+
end
|
8
|
+
|
9
|
+
# Write data to path as a Mail message.
|
10
|
+
def dump(data, path)
|
11
|
+
super(data.to_s, path)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Serialize messages as Marshalled ruby objects
|
2
|
+
class Maildir::Serializer::Marshal < Maildir::Serializer::Base
|
3
|
+
# Read data from path and unmarshal it.
|
4
|
+
def load(path)
|
5
|
+
::Marshal.load(super(path))
|
6
|
+
end
|
7
|
+
|
8
|
+
# Marshal data and write it to path.
|
9
|
+
def dump(data, path)
|
10
|
+
super(::Marshal.dump(data), path)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
# Serialize messages as YAML
|
3
|
+
class Maildir::Serializer::YAML < Maildir::Serializer::Base
|
4
|
+
# Read data from path and parse it as YAML.
|
5
|
+
def load(path)
|
6
|
+
::YAML.load(super(path))
|
7
|
+
end
|
8
|
+
|
9
|
+
# Dump data as YAML and writes it to path.
|
10
|
+
def dump(data, path)
|
11
|
+
super(data.to_yaml, path)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# implements subdirs as used by the Courier Mail Server (courier-mta.org)
|
2
|
+
require 'maildir'
|
3
|
+
module Maildir::Subdirs
|
4
|
+
ROOT_NAME = 'INBOX'
|
5
|
+
DELIM = '.'
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.instance_eval do
|
9
|
+
alias_method :inspect_without_subdirs, :inspect
|
10
|
+
alias_method :inspect, :inspect_with_subdirs
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def name
|
15
|
+
root? ? ROOT_NAME : subdir_parts(path).last
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_subdir(name)
|
19
|
+
raise ArgumentError.new("'name' may not contain delimiter character (#{DELIM})") if name.include?(DELIM)
|
20
|
+
full_name = (root? ? [] : subdir_parts(File.basename(path))).push(name).unshift('').join(DELIM)
|
21
|
+
md = Maildir.new(File.join(path, full_name), true)
|
22
|
+
@subdirs << md if @subdirs
|
23
|
+
md
|
24
|
+
end
|
25
|
+
|
26
|
+
# returns the logical mailbox path
|
27
|
+
def mailbox_path
|
28
|
+
@mailbox_path ||= root? ? ROOT_NAME : subdir_parts(File.basename(path)).unshift(ROOT_NAME).join(DELIM)
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns an array of Maildir objects representing the direct subdirectories of this Maildir
|
32
|
+
def subdirs(only_direct=true)
|
33
|
+
if root?
|
34
|
+
@subdirs ||= (Dir.entries(path) - %w(. ..)).select {|e|
|
35
|
+
e =~ /^\./ && File.directory?(File.join(path, e)) && (only_direct ? subdir_parts(e).size == 1 : true)
|
36
|
+
}.map { |e| Maildir.new(File.join(path, e), false) }
|
37
|
+
else
|
38
|
+
my_parts = subdir_parts(File.basename(path))
|
39
|
+
@subdirs ||= root.subdirs(false).select { |md| subdir_parts(File.basename(md.path))[0..-2] == my_parts }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Friendly inspect method
|
44
|
+
def inspect_with_subdirs
|
45
|
+
"#<#{self.class} path=#{@path} mailbox_path=#{mailbox_path}>"
|
46
|
+
end
|
47
|
+
|
48
|
+
# returns the Maildir representing the root directory
|
49
|
+
def root
|
50
|
+
root? ? self : Maildir.new(File.dirname(path), false)
|
51
|
+
end
|
52
|
+
|
53
|
+
# returns true if the parent directory doesn't look like a maildir
|
54
|
+
def root?
|
55
|
+
! ((Dir.entries(File.dirname(path)) & %w(cur new tmp)).size == 3)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def subdir_parts(path)
|
61
|
+
path.sub!(/\/$/, '') # remove trailing slash
|
62
|
+
parts = (path.split(DELIM) - [''])
|
63
|
+
# some clients (e.g. Thunderbird) mess up namespaces so subdirs
|
64
|
+
# end up looking like '.INBOX.Trash' instead of '.Trash'
|
65
|
+
parts.shift if parts.first == ROOT_NAME
|
66
|
+
parts
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Maildir.send(:include, Maildir::Subdirs)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Class for generating unique file names for new messages
|
2
|
+
class Maildir::UniqueName
|
3
|
+
require 'thread' # For mutex support
|
4
|
+
require 'socket' # For getting the hostname
|
5
|
+
class << self
|
6
|
+
# Return a thread-safe increasing counter
|
7
|
+
def counter
|
8
|
+
@counter_mutex ||= Mutex.new
|
9
|
+
@counter_mutex.synchronize do
|
10
|
+
@counter = @counter.to_i + 1
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def create
|
15
|
+
self.new.to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return a unique file name based on strategy
|
20
|
+
def initialize
|
21
|
+
# Use the same time object
|
22
|
+
@now = Time.now
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the name as a string
|
26
|
+
def to_s
|
27
|
+
[left, middle, right].join(".")
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
# The left part of the unique name is the number of seconds from since the
|
32
|
+
# UNIX epoch
|
33
|
+
def left
|
34
|
+
@now.to_i.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
# The middle part contains the microsecond, the process id, and a
|
38
|
+
# per-process incrementing counter
|
39
|
+
def middle
|
40
|
+
"M#{microsecond}P#{process_id}Q#{delivery_count}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# The right part is the hostname
|
44
|
+
def right
|
45
|
+
Socket.gethostname
|
46
|
+
end
|
47
|
+
|
48
|
+
def secure_random(bytes=8)
|
49
|
+
# File.read("/dev/urandom", bytes).unpack("H*")[0]
|
50
|
+
raise "Not implemented"
|
51
|
+
end
|
52
|
+
|
53
|
+
def inode
|
54
|
+
raise "Not implemented"
|
55
|
+
end
|
56
|
+
|
57
|
+
def device_number
|
58
|
+
raise "Not implemented"
|
59
|
+
end
|
60
|
+
|
61
|
+
def microsecond
|
62
|
+
@now.usec.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def process_id
|
66
|
+
Process.pid.to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
def delivery_count
|
70
|
+
self.class.counter.to_s
|
71
|
+
end
|
72
|
+
end
|
data/maildir.gemspec
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{maildir}
|
8
|
+
s.version = "0.4.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Aaron Suggs", "Niklas E. Cathor"]
|
12
|
+
s.date = %q{2010-01-24}
|
13
|
+
s.description = %q{A ruby library for reading and writing arbitrary messages in DJB's maildir format}
|
14
|
+
s.email = %q{aaron@ktheory.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"LICENSE",
|
22
|
+
"README.rdoc",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"benchmarks/runner",
|
26
|
+
"lib/maildir.rb",
|
27
|
+
"lib/maildir/keywords.rb",
|
28
|
+
"lib/maildir/message.rb",
|
29
|
+
"lib/maildir/serializer/base.rb",
|
30
|
+
"lib/maildir/serializer/json.rb",
|
31
|
+
"lib/maildir/serializer/mail.rb",
|
32
|
+
"lib/maildir/serializer/marshal.rb",
|
33
|
+
"lib/maildir/serializer/yaml.rb",
|
34
|
+
"lib/maildir/subdirs.rb",
|
35
|
+
"lib/maildir/unique_name.rb",
|
36
|
+
"maildir.gemspec",
|
37
|
+
"test/test_helper.rb",
|
38
|
+
"test/test_keywords.rb",
|
39
|
+
"test/test_maildir.rb",
|
40
|
+
"test/test_message.rb",
|
41
|
+
"test/test_serializers.rb",
|
42
|
+
"test/test_subdirs.rb",
|
43
|
+
"test/test_unique_name.rb"
|
44
|
+
]
|
45
|
+
s.homepage = %q{http://github.com/ktheory/maildir}
|
46
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
47
|
+
s.require_paths = ["lib"]
|
48
|
+
s.rubygems_version = %q{1.3.5}
|
49
|
+
s.summary = %q{Read & write messages in the maildir format}
|
50
|
+
s.test_files = [
|
51
|
+
"test/test_serializers.rb",
|
52
|
+
"test/test_keywords.rb",
|
53
|
+
"test/test_helper.rb",
|
54
|
+
"test/test_subdirs.rb",
|
55
|
+
"test/test_message.rb",
|
56
|
+
"test/test_unique_name.rb",
|
57
|
+
"test/test_maildir.rb"
|
58
|
+
]
|
59
|
+
|
60
|
+
if s.respond_to? :specification_version then
|
61
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
62
|
+
s.specification_version = 3
|
63
|
+
|
64
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
65
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
66
|
+
s.add_development_dependency(%q<mail>, [">= 0"])
|
67
|
+
s.add_development_dependency(%q<json>, [">= 0"])
|
68
|
+
s.add_development_dependency(%q<ktheory-fakefs>, [">= 0"])
|
69
|
+
else
|
70
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
71
|
+
s.add_dependency(%q<mail>, [">= 0"])
|
72
|
+
s.add_dependency(%q<json>, [">= 0"])
|
73
|
+
s.add_dependency(%q<ktheory-fakefs>, [">= 0"])
|
74
|
+
end
|
75
|
+
else
|
76
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
77
|
+
s.add_dependency(%q<mail>, [">= 0"])
|
78
|
+
s.add_dependency(%q<json>, [">= 0"])
|
79
|
+
s.add_dependency(%q<ktheory-fakefs>, [">= 0"])
|
80
|
+
end
|
81
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'maildir'
|
6
|
+
|
7
|
+
# Require all the serializers
|
8
|
+
serializers = File.join(File.dirname(__FILE__), "..","lib","maildir","serializer","*")
|
9
|
+
Dir.glob(serializers).each do |serializer|
|
10
|
+
require serializer
|
11
|
+
end
|
12
|
+
|
13
|
+
# Require 'ktheory-fakefs' until issues 28, 29, and 30 are resolved in
|
14
|
+
# defunkt/fakefs. See http://github.com/defunkt/fakefs/issues
|
15
|
+
gem "ktheory-fakefs"
|
16
|
+
require 'fakefs'
|
17
|
+
|
18
|
+
# Create a reusable maildir that's cleaned up when the tests are done
|
19
|
+
def temp_maildir
|
20
|
+
Maildir.new("/tmp/maildir_test")
|
21
|
+
end
|
22
|
+
|
23
|
+
# create the subdir tree:
|
24
|
+
# | INBOX
|
25
|
+
# |-- a
|
26
|
+
# | |-- x
|
27
|
+
# | |-- y
|
28
|
+
# |-- b
|
29
|
+
def setup_subdirs(maildir)
|
30
|
+
%w(a b a.x a.y).each do |x|
|
31
|
+
Maildir.new(File.join(maildir.path, ".#{x}"))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Useful for testing that strings defined & not empty
|
36
|
+
def assert_not_empty(obj, msg='')
|
37
|
+
assert !obj.nil? && !obj.empty?, msg
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'maildir/keywords'
|
3
|
+
class TestKeywords < Test::Unit::TestCase
|
4
|
+
context "A message" do
|
5
|
+
setup do
|
6
|
+
@data = "foo\n"
|
7
|
+
@msg = Maildir::Message.create(temp_maildir, @data)
|
8
|
+
end
|
9
|
+
|
10
|
+
should "remember keywords" do
|
11
|
+
kw = %w(Junk Seen)
|
12
|
+
@msg.keywords = kw
|
13
|
+
assert (@msg.keywords & kw).size == 2
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class TestMaildir < Test::Unit::TestCase
|
3
|
+
|
4
|
+
context "A maildir" do
|
5
|
+
setup do
|
6
|
+
FakeFS::FileSystem.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
should "have a path" do
|
10
|
+
assert_not_empty temp_maildir.path
|
11
|
+
end
|
12
|
+
|
13
|
+
should "create subdirectories by default" do
|
14
|
+
%w(tmp new cur).each do |subdir|
|
15
|
+
subdir_path = temp_maildir.send("#{subdir}_path")
|
16
|
+
assert File.directory?(subdir_path), "Subdir #{subdir} does not exist"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
should "expand paths" do
|
21
|
+
maildir = Maildir.new("~/test_maildir/")
|
22
|
+
expanded_path = File.expand_path("~/test_maildir")
|
23
|
+
expanded_path = File.join(expanded_path, "/")
|
24
|
+
assert_equal expanded_path, maildir.path
|
25
|
+
end
|
26
|
+
|
27
|
+
should "not create directories if specified" do
|
28
|
+
maildir = Maildir.new("/maildir_without_subdirs", false)
|
29
|
+
%w(tmp new cur).each do |subdir|
|
30
|
+
subdir_path = maildir.send("#{subdir}_path")
|
31
|
+
assert !File.directory?(subdir_path), "Subdir #{subdir} exists"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be identical to maildirs with the same path" do
|
36
|
+
new_maildir = Maildir.new(temp_maildir.path)
|
37
|
+
assert_equal temp_maildir.path, new_maildir.path
|
38
|
+
assert_equal temp_maildir, new_maildir
|
39
|
+
end
|
40
|
+
|
41
|
+
should "list a new message" do
|
42
|
+
@message = temp_maildir.add("")
|
43
|
+
messages = temp_maildir.list(:new)
|
44
|
+
assert messages.include?(@message)
|
45
|
+
end
|
46
|
+
|
47
|
+
should "list a cur message" do
|
48
|
+
@message = temp_maildir.add("")
|
49
|
+
@message.process
|
50
|
+
messages = temp_maildir.list(:cur)
|
51
|
+
assert messages.include?(@message)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "Maildirs with the same path" do
|
56
|
+
should "be identical" do
|
57
|
+
another_maildir = Maildir.new(temp_maildir.path, false)
|
58
|
+
assert_equal temp_maildir, another_maildir
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "Maildirs with stale messages in tmp" do
|
63
|
+
should "be found" do
|
64
|
+
stale_path = File.join(temp_maildir.path, "tmp", "stale_message")
|
65
|
+
File.open(stale_path, "w"){|f| f.write("")}
|
66
|
+
stale_time = Time.now - 30*24*60*60 # 1 month ago
|
67
|
+
File.utime(stale_time, stale_time, stale_path)
|
68
|
+
|
69
|
+
stale_tmp = [temp_maildir.get("tmp/stale_message")]
|
70
|
+
assert_equal stale_tmp, temp_maildir.get_stale_tmp
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class TestMessage < Test::Unit::TestCase
|
3
|
+
|
4
|
+
context "An new, unwritten message" do
|
5
|
+
setup do
|
6
|
+
FakeFS::FileSystem.clear
|
7
|
+
@message = Maildir::Message.new(temp_maildir)
|
8
|
+
end
|
9
|
+
|
10
|
+
should "be in :tmp" do
|
11
|
+
assert_equal :tmp, @message.dir
|
12
|
+
assert_match(/tmp/, @message.path)
|
13
|
+
end
|
14
|
+
|
15
|
+
should "have a unique name" do
|
16
|
+
assert_not_empty @message.unique_name
|
17
|
+
end
|
18
|
+
|
19
|
+
should "have a file name" do
|
20
|
+
assert_not_empty @message.filename
|
21
|
+
end
|
22
|
+
|
23
|
+
should "have no info" do
|
24
|
+
assert_nil @message.info
|
25
|
+
end
|
26
|
+
|
27
|
+
should "not be able to set info" do
|
28
|
+
assert_raises RuntimeError do
|
29
|
+
@message.info= "2,FRS"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "A written message" do
|
35
|
+
setup do
|
36
|
+
FakeFS::FileSystem.clear
|
37
|
+
@message = Maildir::Message.new(temp_maildir)
|
38
|
+
@data = "foo"
|
39
|
+
@message.write(@data)
|
40
|
+
end
|
41
|
+
|
42
|
+
should "not be writable" do
|
43
|
+
assert_raise RuntimeError do
|
44
|
+
@message.write("nope!")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
should "have no info" do
|
49
|
+
assert_nil @message.info
|
50
|
+
end
|
51
|
+
|
52
|
+
should "not be able to set info" do
|
53
|
+
assert_raises RuntimeError do
|
54
|
+
@message.info= "2,FRS"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
should "be in new" do
|
59
|
+
assert_equal :new, @message.dir
|
60
|
+
assert_match(/new/, @message.path)
|
61
|
+
end
|
62
|
+
|
63
|
+
should "have a file" do
|
64
|
+
assert File.exists?(@message.path)
|
65
|
+
end
|
66
|
+
|
67
|
+
should "have the correct data" do
|
68
|
+
assert_equal @data, @message.data
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "A processed message" do
|
73
|
+
setup do
|
74
|
+
FakeFS::FileSystem.clear
|
75
|
+
@data = "foo"
|
76
|
+
@message = Maildir::Message.create(temp_maildir, @data)
|
77
|
+
@message.process
|
78
|
+
end
|
79
|
+
|
80
|
+
should "not be writable" do
|
81
|
+
assert_raise RuntimeError do
|
82
|
+
@message.write("nope!")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
should "be in cur" do
|
87
|
+
assert_equal :cur, @message.dir
|
88
|
+
end
|
89
|
+
|
90
|
+
should "have info" do
|
91
|
+
assert_equal Maildir::Message::INFO, @message.info
|
92
|
+
end
|
93
|
+
|
94
|
+
should "set info" do
|
95
|
+
info = "2,FRS"
|
96
|
+
@message.info = "2,FRS"
|
97
|
+
assert_equal @message.info, info
|
98
|
+
assert_match /#{info}$/, @message.path
|
99
|
+
end
|
100
|
+
|
101
|
+
should "add and remove flags" do
|
102
|
+
@message.add_flag('S')
|
103
|
+
assert_equal ['S'], @message.flags
|
104
|
+
|
105
|
+
# Test lowercase
|
106
|
+
@message.add_flag('r')
|
107
|
+
assert_equal ['R', 'S'], @message.flags
|
108
|
+
|
109
|
+
@message.remove_flag('S')
|
110
|
+
assert_equal ['R'], @message.flags
|
111
|
+
|
112
|
+
# Test lowercase
|
113
|
+
@message.remove_flag('r')
|
114
|
+
assert_equal [], @message.flags
|
115
|
+
end
|
116
|
+
|
117
|
+
flag_tests = {
|
118
|
+
"FRS" => ['F', 'R', 'S'],
|
119
|
+
"Sr" => ['R', 'S'], # test capitalization & sorting
|
120
|
+
'' => []
|
121
|
+
}
|
122
|
+
flag_tests.each do |arg, results|
|
123
|
+
should "set flags: #{arg}" do
|
124
|
+
@message.flags = arg
|
125
|
+
assert_equal results, @message.flags
|
126
|
+
path_suffix = "#{Maildir::Message::INFO}#{results.join('')}"
|
127
|
+
assert_match /#{path_suffix}$/, @message.path
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "A destroyed message" do
|
133
|
+
setup do
|
134
|
+
FakeFS::FileSystem.clear
|
135
|
+
@message = Maildir::Message.create(temp_maildir, "foo")
|
136
|
+
@message.destroy
|
137
|
+
end
|
138
|
+
should "be frozen" do
|
139
|
+
assert @message.frozen?, "Message is not frozen"
|
140
|
+
end
|
141
|
+
should "have a nonexistant path" do
|
142
|
+
assert !File.exists?(@message.path), "Message path exists"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "A message with a bad path" do
|
147
|
+
setup do
|
148
|
+
FakeFS::FileSystem.clear
|
149
|
+
@message = temp_maildir.add("")
|
150
|
+
File.delete(@message.path)
|
151
|
+
end
|
152
|
+
|
153
|
+
should "raise error for data" do
|
154
|
+
assert_raise Errno::ENOENT do
|
155
|
+
@message.data
|
156
|
+
end
|
157
|
+
assert @message.frozen?
|
158
|
+
end
|
159
|
+
|
160
|
+
should "not be processed" do
|
161
|
+
old_key = @message.key
|
162
|
+
assert_equal false, @message.process
|
163
|
+
assert @message.frozen?
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
should "reset to the old key after attempt to process" do
|
168
|
+
old_key = @message.key
|
169
|
+
@message.process
|
170
|
+
assert_equal old_key, @message.key
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "Different messages" do
|
175
|
+
setup do
|
176
|
+
FakeFS::FileSystem.clear
|
177
|
+
end
|
178
|
+
|
179
|
+
should "differ" do
|
180
|
+
@message1 = temp_maildir.add("")
|
181
|
+
@message2 = temp_maildir.add("")
|
182
|
+
assert_equal -1, @message1 <=> @message2
|
183
|
+
assert_equal 1, @message2 <=> @message1
|
184
|
+
assert_not_equal @message1, @message2
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "Identical messages" do
|
189
|
+
setup do
|
190
|
+
FakeFS::FileSystem.clear
|
191
|
+
end
|
192
|
+
|
193
|
+
should "be identical" do
|
194
|
+
@message1 = temp_maildir.add("")
|
195
|
+
another_message1 = temp_maildir.get(@message1.key)
|
196
|
+
assert_equal @message1, another_message1
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context "Message#utime" do
|
201
|
+
setup do
|
202
|
+
FakeFS::FileSystem.clear
|
203
|
+
end
|
204
|
+
|
205
|
+
should "update the messages mtime" do
|
206
|
+
@message = temp_maildir.add("")
|
207
|
+
time = Time.now - 60
|
208
|
+
|
209
|
+
@message.utime(time, time)
|
210
|
+
|
211
|
+
# Time should be within 1 second of each other
|
212
|
+
assert_in_delta time, @message.mtime, 1
|
213
|
+
end
|
214
|
+
|
215
|
+
# atime not currently supported in FakeFS
|
216
|
+
# should "update the messages atime" do
|
217
|
+
# @message = temp_maildir.add("")
|
218
|
+
# time = Time.now - 60
|
219
|
+
#
|
220
|
+
# @message.utime(time, time)
|
221
|
+
#
|
222
|
+
# # Time should be within 1 second of each other
|
223
|
+
# assert_in_delta time, @message.atime, 1
|
224
|
+
# end
|
225
|
+
end
|
226
|
+
end
|