nilclass-maildir 0.4.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 +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
|