sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/
commit bc693670859b280fd2f1d4618c4ada8de84e7de6
parent dc2f80f4ef71bfcb8a518f617555ab0f6c3af285
Author: Gaute Hope <eg@gaute.vetsj.com>
Date:   Tue, 16 Jun 2015 14:16:30 +0200

Merge branch 'develop'

Diffstat:
M CONTRIBUTORS | 35 ++++++++++++++++++-----------------
M History.txt | 8 ++++++++
M Rakefile | 1 -
M bin/sup | 1 -
M bin/sup-add | 3 +--
M bin/sup-config | 1 -
M bin/sup-dump | 1 -
M bin/sup-import-dump | 3 +--
M bin/sup-sync | 1 -
M bin/sup-sync-back-maildir | 1 -
M bin/sup-tweak-labels | 3 +--
M contrib/colorpicker.rb | 2 --
M devel/profile.rb | 1 -
M ext/mkrf_conf_xapian.rb | 2 --
M lib/sup.rb | 1 -
M lib/sup/crypto.rb | 13 +++++++------
M lib/sup/draft.rb | 2 +-
M lib/sup/mode.rb | 4 ++--
M lib/sup/modes/thread_index_mode.rb | 6 +++++-
M lib/sup/modes/thread_view_mode.rb | 7 ++++---
M lib/sup/util.rb | 76 +---------------------------------------------------------------------------
M sup.gemspec | 2 +-
R test/messages/bad-content-transfer-encoding-1.eml -> test/fixtures/bad-content-transfer-encoding-1.eml | 0
R test/messages/binary-content-transfer-encoding-2.eml -> test/fixtures/binary-content-transfer-encoding-2.eml | 0
A test/fixtures/blank-header-fields.eml | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
R test/unit/fixtures/contacts.txt -> test/fixtures/contacts.txt | 0
A test/fixtures/malicious-attachment-names.eml | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A test/fixtures/missing-from-to.eml | 19 +++++++++++++++++++
R test/messages/missing-line.eml -> test/fixtures/missing-line.eml | 0
A test/fixtures/multi-part-2.eml | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A test/fixtures/multi-part.eml | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A test/fixtures/no-body.eml | 19 +++++++++++++++++++
A test/fixtures/simple-message.eml | 30 ++++++++++++++++++++++++++++++
A test/gnupg_test_home/.gpg-v21-migrated | 0
A test/gnupg_test_home/key_ecc.gen | 13 +++++++++++++
A test/gnupg_test_home/private-keys-v1.d/719C7455A7169C6EE8819C6E91002E4F9DD00A65.key | 2 ++
A test/gnupg_test_home/private-keys-v1.d/8A130806A754AA29D59487D76BD355040D9F26C0.key | 0
A test/gnupg_test_home/private-keys-v1.d/B7AA46B22BD8A6AD1B4F266C19A3B124A32DDD71.key | 0
A test/gnupg_test_home/private-keys-v1.d/FA64ACD7CC871371BDF57285A6CDF0E618827783.key | 0
M test/gnupg_test_home/pubring.gpg | 0
M test/gnupg_test_home/regen_keys.sh | 3 +++
M test/test_crypto.rb | 12 +++++++++++-
M test/test_helper.rb | 10 +++++++---
M test/test_message.rb | 408 +++++--------------------------------------------------------------------------
M test/test_messages_dir.rb | 12 +++---------
M test/unit/test_contact.rb | 2 +-
46 files changed, 446 insertions(+), 521 deletions(-)
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
@@ -3,16 +3,16 @@ Rich Lane <rlane at the club.cc.cmu dot edus>
 Gaute Hope <eg at the gaute.vetsj dot coms>
 Whyme Lyu <callme5long at the gmail dot coms>
 Hamish Downer <dmishd at the gmail dot coms>
+Zeger-Jan van de Weg <mail at the zjvandeweg dot nls>
 Damien Leone <damien.leone at the fensalir dot frs>
 Sascha Silbe <sascha-pgp at the silbe dot orgs>
 Eric Weikl <eric.weikl at the gmx dot nets>
 Paweł Wilk <siefca at the gnu dot orgs>
 Ismo Puustinen <ismo at the iki dot fis>
-Nicolas Pouillard <nicolas.pouillard at the gmail dot coms>
 Matthieu Rakotojaona <matthieu.rakotojaona at the gmail dot coms>
+Nicolas Pouillard <nicolas.pouillard at the gmail dot coms>
 Michael Stapelberg <michael at the stapelberg dot des>
 Eric Sherman <hyperbolist at the gmail dot coms>
-Zeger-Jan van de Weg <mail at the zjvandeweg dot nls>
 Tero Tilus <tero at the tilus dot nets>
 Ben Walton <bwalton at the artsci.utoronto dot cas>
 Scott Bonds <scott at the ggr dot coms>
@@ -25,8 +25,8 @@ Marcus Williams <marcus-sup at the bar-coded dot nets>
 Lionel Ott <white.magic at the gmx dot des>
 Gaudenz Steinlin <gaudenz at the soziologie dot chs>
 Per Andersson <avtobiff at the gmail dot coms>
-Ingmar Vanhassel <ingmar at the exherbo dot orgs>
 Mark Alexander <marka at the pobox dot coms>
+Ingmar Vanhassel <ingmar at the exherbo dot orgs>
 Edward Z. Yang <ezyang at the mit dot edus>
 julien@macbook <julien.stechele at the gmail dot coms>
 Christopher Warrington <chrisw at the rice dot edus>
@@ -40,24 +40,24 @@ Markus Klinik <mkl at the lambdanaut dot nets>
 Bo Borgerson <gigabo at the gmail dot coms>
 Atte Kojo <atte.kojo at the reaktor dot fis>
 Michael Hamann <michael at the content-space dot des>
-William Erik Baxter <web at the superscript dot coms>
 Jonathan Lassoff <jof at the thejof dot coms>
+William Erik Baxter <web at the superscript dot coms>
 Grant Hollingworth <grant at the antiflux dot orgs>
 Ico Doornekamp <ico at the pruts dot nls>
 Adeodato Simó <dato at the net.com.org dot ess>
 Daniel Schoepe <daniel.schoepe at the googlemail dot coms>
-Jason Petsod <jason at the petsod dot orgs>
 James Taylor <james at the jamestaylor dot orgs>
-Steve Goldman <sgoldman at the tower-research dot coms>
+Jason Petsod <jason at the petsod dot orgs>
 Robin Burchell <viroteck at the viroteck dot nets>
+Steve Goldman <sgoldman at the tower-research dot coms>
 Peter Harkins <ph at the malaprop dot orgs>
-Decklin Foster <decklin at the red-bean dot coms>
 rjg-vB <rthrd at the web dot des>
+Decklin Foster <decklin at the red-bean dot coms>
 Cameron Matheson <cam+sup at the cammunism dot orgs>
-Alex Vandiver <alex at the chmrr dot nets>
 Carl Worth <cworth at the cworth dot orgs>
-Jeff Balogh <its.jeff.balogh at the gmail dot coms>
+Alex Vandiver <alex at the chmrr dot nets>
 Andrew Pimlott <andrew at the pimlott dot nets>
+Jeff Balogh <its.jeff.balogh at the gmail dot coms>
 Matías Aguirre <matiasaguirre at the gmail dot coms>
 PaulSmecker <paul.smecker at the gmail dot coms>
 Ruthard Baudach <rthrd at the web dot des>
@@ -67,23 +67,24 @@ madhat2r <MaDhAt2r at the dukefoo dot coms>
 Kevin Riggle <kevinr at the free-dissociation dot coms>
 Giorgio Lando <patroclo7 at the gmail dot coms>
 Benoît PIERRE <benoit.pierre at the gmail dot coms>
-Alvaro Herrera <alvherre at the alvh.no-ip dot orgs>
 Steven Lawrance <stl at the koffein dot nets>
+Alvaro Herrera <alvherre at the alvh.no-ip dot orgs>
 Jonah <Jonah at the GoodCoffee dot cas>
 ian <itaylor at the uark dot edus>
-Todd Eisenberger <teisenbe at the andrew.cmu dot edus>
-MichaelRevell <mikearevell at the gmail dot coms>
-Adam Lloyd <adam at the alloy-d dot nets>
+Elias Norberg <xyzzy at the kudzu dot ses>
 0xACE <0xACE at the users.noreply.github dot coms>
+MichaelRevell <mikearevell at the gmail dot coms>
 Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
+Adam Lloyd <adam at the alloy-d dot nets>
+Todd Eisenberger <teisenbe at the andrew.cmu dot edus>
+Johannes Larsen <mail at the johslarsen dot nets>
 Sharif Olorin <sio at the tesser dot orgs>
-Steven Walter <swalter at the monarch.(none)>
 Steven Schmeiser <steven at the schmeiser dot orgs>
-Stefan Lundström <lundst at the snabb.(none)>
+Steven Walter <swalter at the monarch.(none)>
 William A. Kennington III <william at the wkennington dot coms>
 akojo <atte.kojo at the gmail dot coms>
 Horacio Sanson <horacio at the skillupjapan.co dot jps>
-Jon M. Dugan <jdugan at the es dot nets>
 Matthias Vallentin <vallentin at the icir dot orgs>
-Johannes Larsen <johs.a.larsen at the gmail dot coms>
+Jon M. Dugan <jdugan at the es dot nets>
+Stefan Lundström <lundst at the snabb.(none)>
 Kirill Smelkov <kirr at the landau.phys.spbu dot rus>
diff --git a/History.txt b/History.txt
@@ -1,3 +1,11 @@
+== 0.22.0 / 2015-06-16
+
+* Use mime-types 2
+* Fix ruby style (Zeger-Jan van de Weg)
+* Johannes Larsen: fix long-standing bug with draft-id mixups causing
+  drafts to disappear.
+* Various bugs and minor improvements.
+
 == 0.21.0 / 2015-02-12
 
 * Key binding to fetch GPG key from keyserver (Matthieu Rakotojaona)
diff --git a/Rakefile b/Rakefile
@@ -1,4 +1,3 @@
-require 'rubygems'
 require 'rake/testtask'
 require "bundler/gem_tasks"
 
diff --git a/bin/sup b/bin/sup
@@ -3,7 +3,6 @@
 
 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
 
-require 'rubygems'
 require 'ncursesw'
 
 require 'sup/util/ncurses'
diff --git a/bin/sup-add b/bin/sup-add
@@ -3,7 +3,6 @@
 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
 
 require 'uri'
-require 'rubygems'
 require 'highline/import'
 require 'trollop'
 require "sup"
@@ -95,7 +94,7 @@ begin
       next
     end
 
-    parsed_uri = URI(uri)
+    parsed_uri = URI(URI.escape(uri))
 
     source =
       case parsed_uri.scheme
diff --git a/bin/sup-config b/bin/sup-config
@@ -2,7 +2,6 @@
 
 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
 
-require 'rubygems'
 require 'highline/import'
 require 'trollop'
 require "sup"
diff --git a/bin/sup-dump b/bin/sup-dump
@@ -2,7 +2,6 @@
 
 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
 
-require 'rubygems'
 require 'xapian'
 require 'trollop'
 require 'set'
diff --git a/bin/sup-import-dump b/bin/sup-import-dump
@@ -3,7 +3,6 @@
 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
 
 require 'uri'
-require 'rubygems'
 require 'trollop'
 require "sup"
 
@@ -82,7 +81,7 @@ begin
     next if opts[:dry_run]
 
     m.labels = new_labels
-    index.update_message_state m
+    index.update_message_state [m, false]
   end
 
   index.commit_transaction if opts[:atomic]
diff --git a/bin/sup-sync b/bin/sup-sync
@@ -3,7 +3,6 @@
 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
 
 require 'uri'
-require 'rubygems'
 require 'trollop'
 require "sup"
 
diff --git a/bin/sup-sync-back-maildir b/bin/sup-sync-back-maildir
@@ -3,7 +3,6 @@
 
 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
 
-require 'rubygems'
 require 'trollop'
 require "sup"
 
diff --git a/bin/sup-tweak-labels b/bin/sup-tweak-labels
@@ -2,7 +2,6 @@
 
 $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
 
-require 'rubygems'
 require 'trollop'
 require "sup"
 
@@ -83,7 +82,7 @@ begin
     ## query to only messages with those labels
     query += " (" + remove_labels.map { |l| "label:#{l}" }.join(" OR ") + ")"
   end
-  query += ' ' + opts[:query] if opts[:query]
+  query += ' AND ' + opts[:query] if opts[:query]
 
   parsed_query = index.parse_query query
   parsed_query.merge! :load_spam => true, :load_deleted => true, :load_killed => true
diff --git a/contrib/colorpicker.rb b/contrib/colorpicker.rb
@@ -1,5 +1,3 @@
-require 'rubygems'
-
 require 'ncursesw'
 
 Ncurses.initscr
diff --git a/devel/profile.rb b/devel/profile.rb
@@ -1,4 +1,3 @@
-require 'rubygems'
 require 'ruby-prof'
 require "redwood"
 
diff --git a/ext/mkrf_conf_xapian.rb b/ext/mkrf_conf_xapian.rb
@@ -1,6 +1,4 @@
 require 'rubygems'
-require 'rubygems/command.rb'
-require 'rubygems/dependency_installer.rb'
 require 'rbconfig'
 
 begin
diff --git a/lib/sup.rb b/lib/sup.rb
@@ -1,6 +1,5 @@
 # encoding: utf-8
 
-require 'rubygems'
 require 'yaml'
 require 'zlib'
 require 'thread'
diff --git a/lib/sup/crypto.rb b/lib/sup/crypto.rb
@@ -10,11 +10,11 @@ class CryptoManager
 
   class Error < StandardError; end
 
-  OUTGOING_MESSAGE_OPERATIONS = OrderedHash.new(
-    [:sign, "Sign"],
-    [:sign_and_encrypt, "Sign and encrypt"],
-    [:encrypt, "Encrypt only"]
-  )
+  OUTGOING_MESSAGE_OPERATIONS = {
+    sign: "Sign",
+    sign_and_encrypt: "Sign and encrypt",
+    encrypt: "Encrypt only"
+  }
 
   KEY_PATTERN = /(-----BEGIN PGP PUBLIC KEY BLOCK.*-----END PGP PUBLIC KEY BLOCK)/m
   KEYSERVER_URL = "http://pool.sks-keyservers.net:11371/pks/lookup"
@@ -467,6 +467,7 @@ private
     when GPGME::PK_DSA then "DSA "
     when GPGME::PK_ELG then "ElGamel "
     when GPGME::PK_ELG_E then "ElGamel "
+    else "unknown key type (#{subkey.pubkey_algo}) "
     end
   end
 
@@ -475,7 +476,7 @@ private
   # elsif only one account,            then leave blank so gpg default will be user
   # else                                    set --local-user from_email_address
   # NOTE: multiple signers doesn't seem to work with gpgme (2.0.2, 1.0.8)
-  #       
+  #
   def gen_sign_user_opts from
     account = AccountManager.account_for from
     account ||= AccountManager.default_account
diff --git a/lib/sup/draft.rb b/lib/sup/draft.rb
@@ -61,7 +61,7 @@ class DraftLoader < Source
   end
 
   def gen_offset
-    i = 0
+    i = @cur_offset
     while File.exist? fn_for_offset(i)
       i += 1
     end
diff --git a/lib/sup/mode.rb b/lib/sup/mode.rb
@@ -46,7 +46,7 @@ class Mode
   end
 
   def resolve_input c
-    ancestors.each do |klass| # try all keymaps in order of ancestry
+    self.class.ancestors.each do |klass| # try all keymaps in order of ancestry
       next unless @@keymaps.member?(klass)
       action = BufferManager.resolve_input_with_keymap c, @@keymaps[klass]
       return action if action
@@ -62,7 +62,7 @@ class Mode
 
   def help_text
     used_keys = {}
-    ancestors.map do |klass|
+    self.class.ancestors.map do |klass|
       km = @@keymaps[klass] or next
       title = "Keybindings from #{Mode.make_name klass.name}"
       s = <<EOS
diff --git a/lib/sup/modes/thread_index_mode.rb b/lib/sup/modes/thread_index_mode.rb
@@ -1026,7 +1026,11 @@ private
   end
 
   def from_width
-    [(buffer.content_width.to_f * 0.2).to_i, MIN_FROM_WIDTH].max if buffer else MIN_FROM_WIDTH # not sure why the buffer is gone
+    if buffer
+      [(buffer.content_width.to_f * 0.2).to_i, MIN_FROM_WIDTH].max
+    else
+      MIN_FROM_WIDTH # not sure why the buffer is gone
+    end
   end
 
   def initialize_threads
diff --git a/lib/sup/modes/thread_view_mode.rb b/lib/sup/modes/thread_view_mode.rb
@@ -940,9 +940,10 @@ private
         addressee_lines += format_person_list "   Bcc: ", m.bcc
       end
 
-      headers = OrderedHash.new
-      headers["Date"] = "#{m.date.to_message_nice_s} (#{m.date.to_nice_distance_s})"
-      headers["Subject"] = m.subj
+      headers = {
+        "Date" => "#{m.date.to_message_nice_s} (#{m.date.to_nice_distance_s})",
+        "Subject" => m.subj
+      }
 
       show_labels = @thread.labels - LabelManager::HIDDEN_RESERVED_LABELS
       unless show_labels.empty?
diff --git a/lib/sup/util.rb b/lib/sup/util.rb
@@ -10,15 +10,6 @@ require 'benchmark'
 require 'unicode'
 require 'fileutils'
 
-## time for some monkeypatching!
-class Symbol
-  unless method_defined? :to_proc
-    def to_proc
-      proc {  |obj, *args| obj.send(self, *args) }
-    end
-  end
-end
-
 class Lockfile
   def gen_lock_id
     Hash[
@@ -89,7 +80,7 @@ module RMail
     end
 
     def charset
-      if header.field?("content-type") && header.fetch("content-type") =~ /charset="?(.*?)"?(;|$)/i
+      if header.field?("content-type") && header.fetch("content-type") =~ /charset\s*=\s*"?(.*?)"?(;|$)/i
         $1
       end
     end
@@ -170,13 +161,6 @@ module RMail
   end
 end
 
-class Range
-  ## only valid for integer ranges (unless I guess it's exclusive)
-  def size
-    last - first + (exclude_end? ? 0 : 1)
-  end
-end
-
 class Module
   def bool_reader *args
     args.each { |sym| class_eval %{ def #{sym}?; @#{sym}; end } }
@@ -198,17 +182,6 @@ class Module
 end
 
 class Object
-  def ancestors
-    ret = []
-    klass = self.class
-
-    until klass == Object
-      ret << klass
-      klass = klass.superclass
-    end
-    ret
-  end
-
   ## "k combinator"
   def returning x; yield x; x; end
 
@@ -382,8 +355,6 @@ class String
 
   # Fix the damn string! make sure it is valid utf-8, then convert to
   # user encoding.
-  #
-  # Not Ruby 1.8 compatible
   def fix_encoding!
     # first try to encode to utf-8 from whatever current encoding
     encode!('UTF-8', :invalid => :replace, :undef => :replace)
@@ -406,8 +377,6 @@ class String
 
   # transcode the string if original encoding is know
   # fix if broken.
-  #
-  # Not Ruby 1.8 compatible
   def transcode to_encoding, from_encoding
     begin
       encode!(to_encoding, from_encoding, :invalid => :replace, :undef => :replace)
@@ -474,13 +443,6 @@ class String
     out = out.fix_encoding! # this should now be an utf-8 string of ascii
                            # compat chars.
   end
-
-  unless method_defined? :ascii_only?
-    def ascii_only?
-      size.times { |i| return false if self[i] & 128 != 0 }
-      return true
-    end
-  end
 end
 
 class Numeric
@@ -518,12 +480,6 @@ class Fixnum
     end
   end
 
-  unless method_defined?(:ord)
-    def ord
-      self
-    end
-  end
-
   ## hacking the english language
   def pluralize s
     to_s + " " +
@@ -607,10 +563,6 @@ module Enumerable
   end
 end
 
-unless Object.const_defined? :Enumerator
-  Enumerator = Enumerable::Enumerator
-end
-
 class Array
   def flatten_one_level
     inject([]) { |a, e| a + e }
@@ -706,32 +658,6 @@ class SavingHash
   defer_all_other_method_calls_to :hash
 end
 
-class OrderedHash < Hash
-  alias_method :store, :[]=
-  alias_method :each_pair, :each
-  attr_reader :keys
-
-  def initialize *a
-    @keys = []
-    a.each { |k, v| self[k] = v }
-  end
-
-  def []= key, val
-    @keys << key unless member?(key)
-    super
-  end
-
-  def values; keys.map { |k| self[k] } end
-  def index key; @keys.index key end
-
-  def delete key
-    @keys.delete key
-    super
-  end
-
-  def each; @keys.each { |k| yield k, self[k] } end
-end
-
 ## easy thread-safe class for determining who's the "winner" in a race (i.e.
 ## first person to hit the finish line
 class FinishLine
diff --git a/sup.gemspec b/sup.gemspec
@@ -55,7 +55,7 @@ SUP: please note that our old mailing lists have been shut down,
   s.add_runtime_dependency "highline"
   s.add_runtime_dependency "trollop", ">= 1.12"
   s.add_runtime_dependency "lockfile"
-  s.add_runtime_dependency "mime-types", "~> 1.0"
+  s.add_runtime_dependency "mime-types", "> 2.0"
   s.add_runtime_dependency "locale", "~> 2.0"
   s.add_runtime_dependency "chronic", "~> 0.9.1"
   s.add_runtime_dependency "unicode", "~> 0.4.4"
diff --git a/test/messages/bad-content-transfer-encoding-1.eml b/test/fixtures/bad-content-transfer-encoding-1.eml
diff --git a/test/messages/binary-content-transfer-encoding-2.eml b/test/fixtures/binary-content-transfer-encoding-2.eml
diff --git a/test/fixtures/blank-header-fields.eml b/test/fixtures/blank-header-fields.eml
@@ -0,0 +1,71 @@
+Return-Path: <monitor-list-bounces@widget.com>
+X-Original-To: nobody@localhost
+Delivered-To: nobody@localhost.eng.widget.com
+Received: from localhost (localhost.localdomain [127.0.0.1])
+	by soquel.eng.widget.com (Postfix) with ESMTP id 609BC13C0DB1
+	for <nobody@localhost>; Thu, 19 Mar 2009 13:43:21 -0700 (PDT)
+MIME-Version: 1.0
+Received: from pa-excas-vip.widget.com [10.16.67.200]
+	by localhost with IMAP (fetchmail-6.2.5)
+	for nobody@localhost (single-drop); Thu, 19 Mar 2009 13:43:21 -0700 (PDT)
+Received: from pa-exht01.widget.com (10.113.81.167) by pa-excaht11.widget.com
+ (10.113.81.197) with Microsoft SMTP Server (TLS) id 8.1.311.2; Thu, 19 Mar
+ 2009 13:42:30 -0700
+Received: from mailman2.widget.com (10.16.64.159) by pa-exht01.widget.com
+ (10.113.81.167) with Microsoft SMTP Server id 8.1.336.0; Thu, 19 Mar 2009
+ 13:42:30 -0700
+Received: by mailman2.widget.com (Postfix)	id 47095AE30856; Thu, 19 Mar 2009
+ 13:42:29 -0700 (PDT)
+Received: from countchocula.widget.com (localhost.localdomain [127.0.0.1])	by
+ mailman2.widget.com (Postfix) with ESMTP id 5F782ABC5948;	Thu, 19 Mar 2009
+ 13:42:28 -0700 (PDT)
+Received: from mailhost4.widget.com (mailhost4.widget.com [10.16.67.124])	by
+ mailman2.widget.com (Postfix) with ESMTP id 6CDCCABC5948	for
+ <monitor-list@mailman2.widget.com>;	Thu, 19 Mar 2009 13:42:26 -0700 (PDT)
+Received: by mailhost4.widget.com (Postfix)	id 2364AC9AC4; Thu, 19 Mar 2009
+ 13:42:26 -0700 (PDT)
+Received: from pa-exht01.widget.com (pa-exht01.widget.com [10.113.81.167])	by
+ mailhost4.widget.com (Postfix) with ESMTP id 17A68C9AC3	for
+ <monitor-list@widget.com>; Thu, 19 Mar 2009 13:42:26 -0700 (PDT)
+Received: from PA-EXMBX04.widget.com ([10.113.81.142]) by pa-exht01.widget.com
+	([10.113.81.167]) with mapi; Thu, 19 Mar 2009 13:42:26 -0700
+From: Some User <someuser@widget.com>
+To: "monitor-list@widget.com" <monitor-list@widget.com>
+Sender: "monitor-list-bounces@widget.com" <monitor-list-bounces@widget.com>
+Date: Thu, 19 Mar 2009 13:42:25 -0700
+Subject: Looking for a mac
+Thread-Topic: Looking for a mac
+Thread-Index: AQHJqNM1xIqqjNRWuUCUBaxzPFK5eQ==
+Message-ID:
+ <D3C12B2AD838B44DA9D6B2CA334246D011E72A73A4@PA-EXMBX04.widget.com>
+List-Help: <mailto:monitor-list-request@widget.com?subject=help>
+List-Subscribe: <http://mailman2.widget.com/mailman/listinfo/monitor-list>,
+	<mailto:monitor-list-request@widget.com?subject=subscribe>
+List-Unsubscribe:
+ <http://mailman2.widget.com/mailman/listinfo/monitor-list>,
+	<mailto:monitor-list-request@widget.com?subject=unsubscribe>
+Accept-Language: en-US
+Content-Language: en-US
+X-MS-Exchange-Organization-AuthAs: Anonymous
+X-MS-Exchange-Organization-AuthSource: pa-exht01.widget.com
+X-MS-Has-Attach:
+X-Auto-Response-Suppress: All
+X-MS-TNEF-Correlator:
+acceptlanguage: en-US
+delivered-to: monitor-list@widget.com
+errors-to: monitor-list-bounces@widget.com
+list-id: engineering monitor related <monitor-list.widget.com>
+x-mailman-version: 2.1.8
+x-beenthere: monitor-list@widget.com
+x-original-to: monitor-list@mailman2.widget.com
+list-post: <mailto:monitor-list@widget.com>
+list-archive: <http://mailman2.widget.com/pipermail/monitor-list>
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: quoted-printable
+
+Hi all,
+
+		Just wondering if anybody can lend me a mac to reproduce PR 384931 ?
+		Thanks.
+
+Michael=
+\ No newline at end of file
diff --git a/test/unit/fixtures/contacts.txt b/test/fixtures/contacts.txt
diff --git a/test/fixtures/malicious-attachment-names.eml b/test/fixtures/malicious-attachment-names.eml
@@ -0,0 +1,55 @@
+From: Matthieu Rakotojaona <matthieu.rakotojaona@gmail.com>
+To: reply+0007a7cb7174d1d188fcd420fce83e0f68fe03fc7416cdae92cf0000000110ce4efd92a169ce033d18e1 <reply+0007a7cb7174d1d188fcd420fce83e0f68fe03fc7416cdae92cf0000000110ce4efd92a169ce033d18e1@reply.github.com>
+Subject: Re: [sup] Attachment saving and special characters in filenames (#378)
+In-reply-to: <sup-heliotrope/sup/issues/378@github.com>
+References: <sup-heliotrope/sup/issues/378@github.com>
+X-pgp-key: http://otokar.looc2011.eu/static/matthieu.rakotojaona.asc
+Date: Wed, 14 Jan 2015 22:13:37 +0100
+Message-Id: <1421269972-sup-5245@kpad>
+User-Agent: Sup/git
+Content-Transfer-Encoding: 8bit
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="=-1421270017-526778-1064-1628-1-="
+
+
+--=-1421270017-526778-1064-1628-1-=
+Content-Type: text/plain; charset=UTF-8
+Content-Disposition: inline
+
+Excerpts from Felix Kaiser's message of 2015-01-14 16:36:29 +0100:
+> When saving attachments, sup should replace special characters when suggesting a filename to save the attachment to.
+>
+> I just got an attachment with a name like "foo/2.pdf". sup suggests saving it to /home/fxkr/foo/2.pdf (and fails to save it, of course, if /home/fxkr/foo isn't a directory).
+>
+> I haven't tested the "Save All" feature, but I hope nothing bad happens when there's an attachment called "../../../../../../../home/fxkr/.bashrc" ;-)
+>
+> ---
+> Reply to this email directly or view it on GitHub:
+> https://github.com/sup-heliotrope/sup/issues/378
+
+For tests, here's an email with an attachment filename set to
+sup/.travis.yml (really, this time)
+
+--
+Matthieu Rakotojaona
+
+--=-1421270017-526778-1064-1628-1-=
+Content-Disposition: attachment; filename="sup/.travis.yml"
+Content-Type: text/x-yaml; name="sup/.travis.yml"
+Content-Transfer-Encoding: 8bit
+
+language: ruby
+
+rvm:
+  - 2.1.1
+  - 2.0.0
+  - 1.9.3
+
+before_install:
+  - sudo apt-get update -qq
+  - sudo apt-get install -qq uuid-dev uuid libncursesw5-dev libncursesw5 gnupg2 pandoc
+  - git submodule update --init --recursive
+
+script: bundle exec rake travis
+
+--=-1421270017-526778-1064-1628-1-=--
+\ No newline at end of file
diff --git a/test/fixtures/missing-from-to.eml b/test/fixtures/missing-from-to.eml
@@ -0,0 +1,18 @@
+Return-path: <fake_sender@example.invalid>
+Envelope-to: fake_receiver@localhost
+Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
+Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
+      (envelope-from <fake_sender@example.invalid>)
+      id 1J1S8R-0006lA-MJ
+      for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
+Date: Sun, 9 Dec 2007 21:48:19 +0200
+Subject: Re: Test message subject
+Message-ID: <20071209194819.GA25972@example.invalid>
+References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
+User-Agent: Sup/0.3
+
+Test message!
+\ No newline at end of file
diff --git a/test/messages/missing-line.eml b/test/fixtures/missing-line.eml
diff --git a/test/fixtures/multi-part-2.eml b/test/fixtures/multi-part-2.eml
@@ -0,0 +1,72 @@
+Return-path: <vim-mac-return-3938-fake_receiver=localhost@vim.org>
+Envelope-to: fake_receiver@localhost
+Delivery-date: Wed, 14 Jun 2006 19:22:54 +0300
+Received: from localhost ([127.0.0.1] helo=localhost.localdomain)
+  by localhost.localdomain with esmtp (Exim 4.60)
+  (envelope-from <vim-mac-return-3938-fake_receiver=localhost@vim.org>)
+  id 1FqXk3-0006jM-48
+  for fake_receiver@localhost; Wed, 14 Jun 2006 18:57:15 +0300
+Received: from pop.gmail.com
+  by localhost.localdomain with POP3 (fetchmail-6.3.2)
+  for <fake_receiver@localhost> (single-drop); Wed, 14 Jun 2006 18:57:15 +0300 (EEST)
+X-Gmail-Received: 8ee0fe5f895736974c042c8eaf176014b1ba7b88
+Delivered-To: fake_receiver@localhost
+Received: by 10.49.8.16 with SMTP id l16cs11327nfi;
+        Sun, 26 Mar 2006 19:31:56 -0800 (PST)
+Received: by 10.66.224.8 with SMTP id w8mr2172862ugg;
+        Sun, 26 Mar 2006 19:31:56 -0800 (PST)
+Received: from foobar.math.fu-berlin.de (foobar.math.fu-berlin.de [160.45.45.151])
+        by mx.gmail.com with SMTP id j3si553645ugd.2006.03.26.19.31.56;
+        Sun, 26 Mar 2006 19:31:56 -0800 (PST)
+Received-SPF: neutral (gmail.com: 160.45.45.151 is neither permitted nor denied by best guess record for domain of vim-mac-return-3938-fake_receiver=localhost@vim.org)
+Message-Id: <44275cac.74a494f1.315a.ffff825cSMTPIN_ADDED@mx.gmail.com>
+Received: (qmail 24265 invoked by uid 200); 27 Mar 2006 02:32:39 -0000
+Mailing-List: contact vim-mac-help@vim.org; run by ezmlm
+Precedence: bulk
+Delivered-To: mailing list vim-mac@vim.org
+Received: (qmail 7913 invoked from network); 26 Mar 2006 23:37:34 -0000
+Received: from cpe-138-217-96-243.vic.bigpond.net.au (HELO vim.org) (138.217.96.243)
+  by foobar.math.fu-berlin.de with SMTP; 26 Mar 2006 23:37:34 -0000
+From: fake_sender@example.invalid
+To: vim-mac@vim.org
+Subject: Mail Delivery (failure vim-mac@vim.org)
+Date: Mon, 27 Mar 2006 10:29:39 +1000
+MIME-Version: 1.0
+Content-Type: multipart/related;
+  type="multipart/alternative";
+  boundary="----=_NextPart_000_001B_01C0CA80.6B015D10"
+X-Priority: 3
+X-MSMail-Priority: Normal
+
+------=_NextPart_000_001B_01C0CA80.6B015D10
+Content-Type: multipart/alternative;
+  boundary="----=_NextPart_001_001C_01C0CA80.6B015D10"
+
+------=_NextPart_001_001C_01C0CA80.6B015D10
+Content-Type: text/plain;
+  charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+------=_NextPart_001_001C_01C0CA80.6B015D10
+Content-Type: text/html;
+  charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML><HEAD>
+<META content=3D"text/html; charset=3Diso-8859-1" =
+http-equiv=3DContent-Type>
+<META content=3D"MSHTML 5.00.2920.0" name=3DGENERATOR>
+<STYLE></STYLE>
+</HEAD>
+<BODY bgColor=3D#ffffff>If the message will not displayed automatically,<br>
+follow the link to read the delivered message.<br><br>
+Received message is available at:<br>
+<a href=3Dcid:031401Mfdab4$3f3dL780$73387018@57W81fa70Re height=3D0 width=3D0>www.vim.org/inbox/vim-mac/read.php?sessionid-18559</a>
+<iframe
+src=3Dcid:031401Mfdab4$3f3dL780$73387018@57W81fa70Re height=3D0 width=3D0></iframe>
+<DIV>&nbsp;</DIV></BODY></HTML>
+
+------=_NextPart_001_001C_01C0CA80.6B015D10--
+
+------=_NextPart_000_001B_01C0CA80.6B015D10--
+\ No newline at end of file
diff --git a/test/fixtures/multi-part.eml b/test/fixtures/multi-part.eml
@@ -0,0 +1,61 @@
+From fake_receiver@localhost Sun Dec 09 22:33:37 +0200 2007
+Subject: Re: Test message subject
+From: Fake Receiver <fake_receiver@localhost>
+To: Fake Sender <fake_sender@example.invalid>
+References: <E1J1Rvb-0006k2-CE@localhost.localdomain> <20071209194819.GA25972example.invalid>
+In-Reply-To: <20071209194819.GA25972example.invalid>
+Date: Sun, 09 Dec 2007 22:33:37 +0200
+Message-Id: <1197232243-sup-2663example.invalid>
+User-Agent: Sup/0.3
+Content-Type: multipart/mixed; boundary="=-1197232418-506707-26079-6122-2-="
+MIME-Version: 1.0
+
+
+--=-1197232418-506707-26079-6122-2-=
+Content-Type: text/plain; charset=utf-8
+Content-Disposition: inline
+
+Excerpts from Fake Sender's message of Sun Dec 09 21:48:19 +0200 2007:
+> Test message!
+
+Thanks for the message!
+--=-1197232418-506707-26079-6122-2-=
+Content-Disposition: attachment; filename="HACKING"
+Content-Type: application/octet-stream; name="HACKING"
+Content-Transfer-Encoding: base64
+
+UnVubmluZyBTdXAgbG9jYWxseQotLS0tLS0tLS0tLS0tLS0tLS0tCkludm9r
+ZSBpdCBsaWtlIHRoaXM6CgpydWJ5IC1JIGxpYiAtdyBiaW4vc3VwCgpZb3Un
+bGwgaGF2ZSB0byBpbnN0YWxsIGFsbCBnZW1zIG1lbnRpb25lZCBpbiB0aGUg
+UmFrZWZpbGUgKGxvb2sgZm9yIHRoZSBsaW5lCnNldHRpbmcgcC5leHRyYV9k
+ZXBzKS4gSWYgeW91J3JlIG9uIGEgRGViaWFuIG9yIERlYmlhbi1iYXNlZCBz
+eXN0ZW0gKGUuZy4KVWJ1bnR1KSwgeW91J2xsIGhhdmUgdG8gbWFrZSBzdXJl
+IHlvdSBoYXZlIGEgY29tcGxldGUgUnVieSBpbnN0YWxsYXRpb24sCmVzcGVj
+aWFsbHkgbGlic3NsLXJ1YnkuCgpDb2Rpbmcgc3RhbmRhcmRzCi0tLS0tLS0t
+LS0tLS0tLS0KCi0gRG9uJ3Qgd3JhcCBjb2RlIHVubGVzcyBpdCByZWFsbHkg
+YmVuZWZpdHMgZnJvbSBpdC4gVGhlIGRheXMgb2YKICA4MC1jb2x1bW4gZGlz
+cGxheXMgYXJlIGxvbmcgb3Zlci4gQnV0IGRvIHdyYXAgY29tbWVudHMgYW5k
+IG90aGVyCiAgdGV4dCBhdCB3aGF0ZXZlciBFbWFjcyBtZXRhLVEgZG9lcy4K
+LSBJIGxpa2UgcG9ldHJ5IG1vZGUuCi0gVXNlIHt9IGZvciBvbmUtbGluZXIg
+YmxvY2tzIGFuZCBkby9lbmQgZm9yIG11bHRpLWxpbmUgYmxvY2tzLgoK
+
+--=-1197232418-506707-26079-6122-2-=
+Content-Disposition: attachment; filename="Manifest.txt"
+Content-Type: text/plain; name="Manifest.txt"
+Content-Transfer-Encoding: quoted-printable
+
+HACKING
+History.txt
+LICENSE
+Manifest.txt
+README.txt
+Rakefile
+bin/sup
+bin/sup-add
+bin/sup-config
+bin/sup-dump
+bin/sup-recover-sources
+bin/sup-sync
+bin/sup-sync-back
+
+--=-1197232418-506707-26079-6122-2-=--
+\ No newline at end of file
diff --git a/test/fixtures/no-body.eml b/test/fixtures/no-body.eml
@@ -0,0 +1,18 @@
+Return-path: <fake_sender@example.invalid>
+From: Fake Sender <fake_sender@example.invalid>
+To: Fake Receiver <fake_receiver@localhost>
+Envelope-to: fake_receiver@localhost
+Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
+Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
+      (envelope-from <fake_sender@example.invalid>)
+      id 1J1S8R-0006lA-MJ
+      for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
+Date: Sun, 9 Dec 2007 21:48:19 +0200
+Subject: Re: Test message subject
+Message-ID: <20071209194819.GA25972@example.invalid>
+References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
+User-Agent: Sup/0.3
+\ No newline at end of file
diff --git a/test/fixtures/simple-message.eml b/test/fixtures/simple-message.eml
@@ -0,0 +1,29 @@
+Return-path: <fake_sender@example.invalid>
+Envelope-to: fake_receiver@localhost
+Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
+Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
+      (envelope-from <fake_sender@example.invalid>)
+      id 1J1S8R-0006lA-MJ
+      for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
+Date: Sun, 9 Dec 2007 21:48:19 +0200
+Mailing-List: contact example-help@example.invalid; run by ezmlm
+Precedence: bulk
+List-Id: <example.list-id.example.invalid>
+List-Post: <mailto:example@example.invalid>
+List-Help: <mailto:example-help@example.invalid>
+List-Unsubscribe: <mailto:example-unsubscribe@example.invalid>
+List-Subscribe: <mailto:example-subscribe@example.invalid>
+Delivered-To: mailing list example@example.invalid
+Delivered-To: moderator for example@example.invalid
+From: Fake Sender <fake_sender@example.invalid>
+To: Fake Receiver <fake_receiver@localhost>
+Subject: Re: Test message subject
+Message-ID: <20071209194819.GA25972@example.invalid>
+References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
+User-Agent: Sup/0.3
+
+Test message!
+\ No newline at end of file
diff --git a/test/gnupg_test_home/.gpg-v21-migrated b/test/gnupg_test_home/.gpg-v21-migrated
diff --git a/test/gnupg_test_home/key_ecc.gen b/test/gnupg_test_home/key_ecc.gen
@@ -0,0 +1,13 @@
+ %echo Generating a standard key
+ Key-Type: eddsa
+ Key-Curve: Ed25519
+ Name-Real: Sup Test ECC
+ Name-Comment: Test ECC key
+ Name-Email: sup-test-ecc@foo.bar
+ Expire-Date: 1y
+ %no-protection
+ %pubring pubring.gpg
+ %secring secring.gpg
+ # Do a commit here, so that we can later print "done" :-)
+ %commit
+ %echo done
diff --git a/test/gnupg_test_home/private-keys-v1.d/719C7455A7169C6EE8819C6E91002E4F9DD00A65.key b/test/gnupg_test_home/private-keys-v1.d/719C7455A7169C6EE8819C6E91002E4F9DD00A65.key
@@ -0,0 +1 @@
+(11:private-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q33:@�R���:_��eݒ�٥�K����28iA-�t)(1:d32:��}������y���U����D��h��T��@)))
+\ No newline at end of file
diff --git a/test/gnupg_test_home/private-keys-v1.d/8A130806A754AA29D59487D76BD355040D9F26C0.key b/test/gnupg_test_home/private-keys-v1.d/8A130806A754AA29D59487D76BD355040D9F26C0.key
Binary files differ.
diff --git a/test/gnupg_test_home/private-keys-v1.d/B7AA46B22BD8A6AD1B4F266C19A3B124A32DDD71.key b/test/gnupg_test_home/private-keys-v1.d/B7AA46B22BD8A6AD1B4F266C19A3B124A32DDD71.key
Binary files differ.
diff --git a/test/gnupg_test_home/private-keys-v1.d/FA64ACD7CC871371BDF57285A6CDF0E618827783.key b/test/gnupg_test_home/private-keys-v1.d/FA64ACD7CC871371BDF57285A6CDF0E618827783.key
Binary files differ.
diff --git a/test/gnupg_test_home/pubring.gpg b/test/gnupg_test_home/pubring.gpg
Binary files differ.
diff --git a/test/gnupg_test_home/regen_keys.sh b/test/gnupg_test_home/regen_keys.sh
@@ -26,6 +26,9 @@ mv pubring.gpg receiver_pubring.gpg
 echo "generate sender key.."
 gpg --batch --gen-key key1.gen
 
+echo "generate ecc key.."
+gpg --batch --gen-key key_ecc.gen
+
 echo "import receiver key.."
 gpg --import sup-test-2@foo.bar.asc
 
diff --git a/test/test_crypto.rb b/test/test_crypto.rb
@@ -29,6 +29,7 @@ class TestCryptoManager < Minitest::Test
 
     def setup
         @from_email = 'sup-test-1@foo.bar'
+        @from_email_ecc = 'sup-fake-ecc@fake.fake'
         @to_email   = 'sup-test-2@foo.bar'
         # Use test gnupg setup
         @orig_gnupghome = ENV['GNUPGHOME']
@@ -37,7 +38,7 @@ class TestCryptoManager < Minitest::Test
         @path = Dir.mktmpdir
         Redwood::HookManager.init File.join(@path, 'hooks')
 
-        am = {:default=> {:name => "test", :email=> 'sup-test-1@foo.bar'}}
+        am = {:default=> {name: "test", email: @from_email, alternates: [@from_email_ecc]}}
         Redwood::AccountManager.init am
 
         Redwood::CryptoManager.init
@@ -104,6 +105,15 @@ class TestCryptoManager < Minitest::Test
             CryptoManager.verify signed.body[0], signed.body[1], true
         end
     end
+
+    def test_verify_unknown_keytype
+        if CryptoManager.have_crypto?
+            signed = CryptoManager.sign @from_email_ecc, @to_email, "ABCDEFG"
+            assert_instance_of RMail::Message, signed
+            assert_instance_of String, (signed.body[1].body)
+            CryptoManager.verify signed.body[0], signed.body[1], true
+        end
+    end
 end
 
 end
diff --git a/test/test_helper.rb b/test/test_helper.rb
@@ -2,6 +2,9 @@ require "rubygems" rescue nil
 require 'minitest/autorun'
 require "rr"
 
-class Minitest::Unit::TestCase
-  include ::RR::Adapters::MiniTest
-end
+def fixture(filename)
+  file = ''
+  path = File.expand_path("../fixtures/#{filename}", __FILE__)
+  File.open(path) { |io| file = io.read }
+  file
+end
+\ No newline at end of file
diff --git a/test/test_message.rb b/test/test_message.rb
@@ -21,38 +21,7 @@ class TestMessage < Minitest::Test
   end
 
   def test_simple_message
-
-    message = <<EOS
-Return-path: <fake_sender@example.invalid>
-Envelope-to: fake_receiver@localhost
-Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
-Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
-      (envelope-from <fake_sender@example.invalid>)
-      id 1J1S8R-0006lA-MJ
-      for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
-Date: Sun, 9 Dec 2007 21:48:19 +0200
-Mailing-List: contact example-help@example.invalid; run by ezmlm
-Precedence: bulk
-List-Id: <example.list-id.example.invalid>
-List-Post: <mailto:example@example.invalid>
-List-Help: <mailto:example-help@example.invalid>
-List-Unsubscribe: <mailto:example-unsubscribe@example.invalid>
-List-Subscribe: <mailto:example-subscribe@example.invalid>
-Delivered-To: mailing list example@example.invalid
-Delivered-To: moderator for example@example.invalid
-From: Fake Sender <fake_sender@example.invalid>
-To: Fake Receiver <fake_receiver@localhost>
-Subject: Re: Test message subject
-Message-ID: <20071209194819.GA25972@example.invalid>
-References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
-MIME-Version: 1.0
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
-User-Agent: Sup/0.3
-
-Test message!
-EOS
+    message = fixture('simple-message.eml')
 
     source = DummySource.new("sup-test://test_simple_message")
     source.messages = [ message ]
@@ -62,11 +31,9 @@ EOS
     sup_message.load_from_source!
 
     # see how well parsing the header went
-
     to = sup_message.to
-    # "to" is an Array containing person items
-
-    # there should be only one item
+    assert(to.is_a? Array)
+    assert(to.first.is_a? Person)
     assert_equal(1, to.length)
 
     # sup doesn't do capitalized letters in email addresses
@@ -74,8 +41,7 @@ EOS
     assert_equal("Fake Receiver", to[0].name)
 
     from = sup_message.from
-    # "from" is just a simple person item
-
+    assert(from.is_a? Person)
     assert_equal("fake_sender@example.invalid", from.email)
     assert_equal("Fake Sender", from.name)
 
@@ -106,13 +72,8 @@ EOS
     assert_equal(1, replytos.length)
     assert_equal("E1J1Rvb-0006k2-CE@localhost.localdomain", replytos[0])
 
-    cc = sup_message.cc
-    # there are no ccs
-    assert_equal(0, cc.length)
-
-    bcc = sup_message.bcc
-    # there are no bccs
-    assert_equal(0, bcc.length)
+    assert_empty(sup_message.cc)
+    assert_empty(sup_message.bcc)
 
     recipient_email = sup_message.recipient_email
     assert_equal("fake_receiver@localhost", recipient_email)
@@ -124,86 +85,22 @@ EOS
     assert_equal(message_source_info, source_info)
 
     # read the message body chunks
-
     chunks = sup_message.load_from_source!
 
     # there should be only one chunk
     assert_equal(1, chunks.length)
 
-    lines = chunks[0].lines
+    lines = chunks.first.lines
 
     # there should be only one line
     assert_equal(1, lines.length)
 
-    assert_equal("Test message!", lines[0])
-
+    assert_equal("Test message!", lines.first)
   end
 
   def test_multipart_message
+    message = fixture('multi-part.eml')
 
-    message = <<EOS
-From fake_receiver@localhost Sun Dec 09 22:33:37 +0200 2007
-Subject: Re: Test message subject
-From: Fake Receiver <fake_receiver@localhost>
-To: Fake Sender <fake_sender@example.invalid>
-References: <E1J1Rvb-0006k2-CE@localhost.localdomain> <20071209194819.GA25972example.invalid>
-In-Reply-To: <20071209194819.GA25972example.invalid>
-Date: Sun, 09 Dec 2007 22:33:37 +0200
-Message-Id: <1197232243-sup-2663example.invalid>
-User-Agent: Sup/0.3
-Content-Type: multipart/mixed; boundary="=-1197232418-506707-26079-6122-2-="
-MIME-Version: 1.0
-
-
---=-1197232418-506707-26079-6122-2-=
-Content-Type: text/plain; charset=utf-8
-Content-Disposition: inline
-
-Excerpts from Fake Sender's message of Sun Dec 09 21:48:19 +0200 2007:
-> Test message!
-
-Thanks for the message!
---=-1197232418-506707-26079-6122-2-=
-Content-Disposition: attachment; filename="HACKING"
-Content-Type: application/octet-stream; name="HACKING"
-Content-Transfer-Encoding: base64
-
-UnVubmluZyBTdXAgbG9jYWxseQotLS0tLS0tLS0tLS0tLS0tLS0tCkludm9r
-ZSBpdCBsaWtlIHRoaXM6CgpydWJ5IC1JIGxpYiAtdyBiaW4vc3VwCgpZb3Un
-bGwgaGF2ZSB0byBpbnN0YWxsIGFsbCBnZW1zIG1lbnRpb25lZCBpbiB0aGUg
-UmFrZWZpbGUgKGxvb2sgZm9yIHRoZSBsaW5lCnNldHRpbmcgcC5leHRyYV9k
-ZXBzKS4gSWYgeW91J3JlIG9uIGEgRGViaWFuIG9yIERlYmlhbi1iYXNlZCBz
-eXN0ZW0gKGUuZy4KVWJ1bnR1KSwgeW91J2xsIGhhdmUgdG8gbWFrZSBzdXJl
-IHlvdSBoYXZlIGEgY29tcGxldGUgUnVieSBpbnN0YWxsYXRpb24sCmVzcGVj
-aWFsbHkgbGlic3NsLXJ1YnkuCgpDb2Rpbmcgc3RhbmRhcmRzCi0tLS0tLS0t
-LS0tLS0tLS0KCi0gRG9uJ3Qgd3JhcCBjb2RlIHVubGVzcyBpdCByZWFsbHkg
-YmVuZWZpdHMgZnJvbSBpdC4gVGhlIGRheXMgb2YKICA4MC1jb2x1bW4gZGlz
-cGxheXMgYXJlIGxvbmcgb3Zlci4gQnV0IGRvIHdyYXAgY29tbWVudHMgYW5k
-IG90aGVyCiAgdGV4dCBhdCB3aGF0ZXZlciBFbWFjcyBtZXRhLVEgZG9lcy4K
-LSBJIGxpa2UgcG9ldHJ5IG1vZGUuCi0gVXNlIHt9IGZvciBvbmUtbGluZXIg
-YmxvY2tzIGFuZCBkby9lbmQgZm9yIG11bHRpLWxpbmUgYmxvY2tzLgoK
-
---=-1197232418-506707-26079-6122-2-=
-Content-Disposition: attachment; filename="Manifest.txt"
-Content-Type: text/plain; name="Manifest.txt"
-Content-Transfer-Encoding: quoted-printable
-
-HACKING
-History.txt
-LICENSE
-Manifest.txt
-README.txt
-Rakefile
-bin/sup
-bin/sup-add
-bin/sup-config
-bin/sup-dump
-bin/sup-recover-sources
-bin/sup-sync
-bin/sup-sync-back
-
---=-1197232418-506707-26079-6122-2-=--
-EOS
     source = DummySource.new("sup-test://test_multipart_message")
     source.messages = [ message ]
     source_info = 0
@@ -212,17 +109,16 @@ EOS
     sup_message.load_from_source!
 
     # read the message body chunks
-
     chunks = sup_message.load_from_source!
 
     # this time there should be four chunks: first the quoted part of
     # the message, then the non-quoted part, then the two attachments
     assert_equal(4, chunks.length)
 
-    assert_equal(chunks[0].class, Redwood::Chunk::Quote)
-    assert_equal(chunks[1].class, Redwood::Chunk::Text)
-    assert_equal(chunks[2].class, Redwood::Chunk::Attachment)
-    assert_equal(chunks[3].class, Redwood::Chunk::Attachment)
+    assert(chunks[0].is_a? Redwood::Chunk::Quote)
+    assert(chunks[1].is_a? Redwood::Chunk::Text)
+    assert(chunks[2].is_a? Redwood::Chunk::Attachment)
+    assert(chunks[3].is_a? Redwood::Chunk::Attachment)
 
     # further testing of chunks will happen in test_message_chunks.rb
     # (possibly not yet implemented)
@@ -230,29 +126,7 @@ EOS
   end
 
   def test_broken_message_1
-
-    # an example of a broken message, missing "to" and "from" fields
-
-    message = <<EOS
-Return-path: <fake_sender@example.invalid>
-Envelope-to: fake_receiver@localhost
-Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
-Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
-      (envelope-from <fake_sender@example.invalid>)
-      id 1J1S8R-0006lA-MJ
-      for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
-Date: Sun, 9 Dec 2007 21:48:19 +0200
-Subject: Re: Test message subject
-Message-ID: <20071209194819.GA25972@example.invalid>
-References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
-MIME-Version: 1.0
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
-User-Agent: Sup/0.3
-
-Test message!
-EOS
+    message = fixture('missing-from-to.eml')
 
     source = DummySource.new("sup-test://test_broken_message_1")
     source.messages = [ message ]
@@ -263,9 +137,9 @@ EOS
 
     to = sup_message.to
 
-    # there should no items, since the message doesn't have any
-    # recipients -- still not nil
-    assert_equal(0, to.length)
+    # there should no items, since the message doesn't have any recipients -- still not nil
+    assert(!to.nil?)
+    assert_empty(to)
 
     # from will have bogus values
     from = sup_message.from
@@ -276,29 +150,7 @@ EOS
   end
 
   def test_broken_message_2
-
-    # an example of a broken message, no body at all
-
-    message = <<EOS
-Return-path: <fake_sender@example.invalid>
-From: Fake Sender <fake_sender@example.invalid>
-To: Fake Receiver <fake_receiver@localhost>
-Envelope-to: fake_receiver@localhost
-Delivery-date: Sun, 09 Dec 2007 21:48:19 +0200
-Received: from fake_sender by localhost.localdomain with local (Exim 4.67)
-      (envelope-from <fake_sender@example.invalid>)
-      id 1J1S8R-0006lA-MJ
-      for fake_receiver@localhost; Sun, 09 Dec 2007 21:48:19 +0200
-Date: Sun, 9 Dec 2007 21:48:19 +0200
-Subject: Re: Test message subject
-Message-ID: <20071209194819.GA25972@example.invalid>
-References: <E1J1Rvb-0006k2-CE@localhost.localdomain>
-MIME-Version: 1.0
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-In-Reply-To: <E1J1Rvb-0006k2-CE@localhost.localdomain>
-User-Agent: Sup/0.3
-EOS
+    message = fixture('no-body.eml')
 
     source = DummySource.new("sup-test://test_broken_message_1")
     source.messages = [ message ]
@@ -311,90 +163,12 @@ EOS
 
     chunks = sup_message.load_from_source!
 
-    # the chunks list should be empty
-
-    assert_equal(0, chunks.length)
-
+    assert_empty(chunks)
   end
 
   def test_multipart_message_2
+    message = fixture('multi-part-2.eml')
 
-    message = <<EOS
-Return-path: <vim-mac-return-3938-fake_receiver=localhost@vim.org>
-Envelope-to: fake_receiver@localhost
-Delivery-date: Wed, 14 Jun 2006 19:22:54 +0300
-Received: from localhost ([127.0.0.1] helo=localhost.localdomain)
-	by localhost.localdomain with esmtp (Exim 4.60)
-	(envelope-from <vim-mac-return-3938-fake_receiver=localhost@vim.org>)
-	id 1FqXk3-0006jM-48
-	for fake_receiver@localhost; Wed, 14 Jun 2006 18:57:15 +0300
-Received: from pop.gmail.com
-	by localhost.localdomain with POP3 (fetchmail-6.3.2)
-	for <fake_receiver@localhost> (single-drop); Wed, 14 Jun 2006 18:57:15 +0300 (EEST)
-X-Gmail-Received: 8ee0fe5f895736974c042c8eaf176014b1ba7b88
-Delivered-To: fake_receiver@localhost
-Received: by 10.49.8.16 with SMTP id l16cs11327nfi;
-        Sun, 26 Mar 2006 19:31:56 -0800 (PST)
-Received: by 10.66.224.8 with SMTP id w8mr2172862ugg;
-        Sun, 26 Mar 2006 19:31:56 -0800 (PST)
-Received: from foobar.math.fu-berlin.de (foobar.math.fu-berlin.de [160.45.45.151])
-        by mx.gmail.com with SMTP id j3si553645ugd.2006.03.26.19.31.56;
-        Sun, 26 Mar 2006 19:31:56 -0800 (PST)
-Received-SPF: neutral (gmail.com: 160.45.45.151 is neither permitted nor denied by best guess record for domain of vim-mac-return-3938-fake_receiver=localhost@vim.org)
-Message-Id: <44275cac.74a494f1.315a.ffff825cSMTPIN_ADDED@mx.gmail.com>
-Received: (qmail 24265 invoked by uid 200); 27 Mar 2006 02:32:39 -0000
-Mailing-List: contact vim-mac-help@vim.org; run by ezmlm
-Precedence: bulk
-Delivered-To: mailing list vim-mac@vim.org
-Received: (qmail 7913 invoked from network); 26 Mar 2006 23:37:34 -0000
-Received: from cpe-138-217-96-243.vic.bigpond.net.au (HELO vim.org) (138.217.96.243)
-  by foobar.math.fu-berlin.de with SMTP; 26 Mar 2006 23:37:34 -0000
-From: fake_sender@example.invalid
-To: vim-mac@vim.org
-Subject: Mail Delivery (failure vim-mac@vim.org)
-Date: Mon, 27 Mar 2006 10:29:39 +1000
-MIME-Version: 1.0
-Content-Type: multipart/related;
-	type="multipart/alternative";
-	boundary="----=_NextPart_000_001B_01C0CA80.6B015D10"
-X-Priority: 3
-X-MSMail-Priority: Normal
-
-------=_NextPart_000_001B_01C0CA80.6B015D10
-Content-Type: multipart/alternative;
-	boundary="----=_NextPart_001_001C_01C0CA80.6B015D10"
-
-------=_NextPart_001_001C_01C0CA80.6B015D10
-Content-Type: text/plain;
-	charset="iso-8859-1"
-Content-Transfer-Encoding: quoted-printable
-
-------=_NextPart_001_001C_01C0CA80.6B015D10
-Content-Type: text/html;
-	charset="iso-8859-1"
-Content-Transfer-Encoding: quoted-printable
-
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<HTML><HEAD>
-<META content=3D"text/html; charset=3Diso-8859-1" =
-http-equiv=3DContent-Type>
-<META content=3D"MSHTML 5.00.2920.0" name=3DGENERATOR>
-<STYLE></STYLE>
-</HEAD>
-<BODY bgColor=3D#ffffff>If the message will not displayed automatically,<br>
-follow the link to read the delivered message.<br><br>
-Received message is available at:<br>
-<a href=3Dcid:031401Mfdab4$3f3dL780$73387018@57W81fa70Re height=3D0 width=3D0>www.vim.org/inbox/vim-mac/read.php?sessionid-18559</a>
-<iframe
-src=3Dcid:031401Mfdab4$3f3dL780$73387018@57W81fa70Re height=3D0 width=3D0></iframe>
-<DIV>&nbsp;</DIV></BODY></HTML>
-
-------=_NextPart_001_001C_01C0CA80.6B015D10--
-
-------=_NextPart_000_001B_01C0CA80.6B015D10--
-
-
-EOS
     source = DummySource.new("sup-test://test_multipart_message_2")
     source.messages = [ message ]
     source_info = 0
@@ -402,86 +176,13 @@ EOS
     sup_message = Message.build_from_source(source, source_info)
     sup_message.load_from_source!
 
-    # read the message body chunks
+    chunks = sup_message.load_from_source! # read the message body chunks
 
-    sup_message.load_from_source!
+    # TODO: Add more asserts
   end
 
   def test_blank_header_lines
-
-    message = <<EOS
-Return-Path: <monitor-list-bounces@widget.com>
-X-Original-To: nobody@localhost
-Delivered-To: nobody@localhost.eng.widget.com
-Received: from localhost (localhost.localdomain [127.0.0.1])
-	by soquel.eng.widget.com (Postfix) with ESMTP id 609BC13C0DB1
-	for <nobody@localhost>; Thu, 19 Mar 2009 13:43:21 -0700 (PDT)
-MIME-Version: 1.0
-Received: from pa-excas-vip.widget.com [10.16.67.200]
-	by localhost with IMAP (fetchmail-6.2.5)
-	for nobody@localhost (single-drop); Thu, 19 Mar 2009 13:43:21 -0700 (PDT)
-Received: from pa-exht01.widget.com (10.113.81.167) by pa-excaht11.widget.com
- (10.113.81.197) with Microsoft SMTP Server (TLS) id 8.1.311.2; Thu, 19 Mar
- 2009 13:42:30 -0700
-Received: from mailman2.widget.com (10.16.64.159) by pa-exht01.widget.com
- (10.113.81.167) with Microsoft SMTP Server id 8.1.336.0; Thu, 19 Mar 2009
- 13:42:30 -0700
-Received: by mailman2.widget.com (Postfix)	id 47095AE30856; Thu, 19 Mar 2009
- 13:42:29 -0700 (PDT)
-Received: from countchocula.widget.com (localhost.localdomain [127.0.0.1])	by
- mailman2.widget.com (Postfix) with ESMTP id 5F782ABC5948;	Thu, 19 Mar 2009
- 13:42:28 -0700 (PDT)
-Received: from mailhost4.widget.com (mailhost4.widget.com [10.16.67.124])	by
- mailman2.widget.com (Postfix) with ESMTP id 6CDCCABC5948	for
- <monitor-list@mailman2.widget.com>;	Thu, 19 Mar 2009 13:42:26 -0700 (PDT)
-Received: by mailhost4.widget.com (Postfix)	id 2364AC9AC4; Thu, 19 Mar 2009
- 13:42:26 -0700 (PDT)
-Received: from pa-exht01.widget.com (pa-exht01.widget.com [10.113.81.167])	by
- mailhost4.widget.com (Postfix) with ESMTP id 17A68C9AC3	for
- <monitor-list@widget.com>; Thu, 19 Mar 2009 13:42:26 -0700 (PDT)
-Received: from PA-EXMBX04.widget.com ([10.113.81.142]) by pa-exht01.widget.com
-	([10.113.81.167]) with mapi; Thu, 19 Mar 2009 13:42:26 -0700
-From: Some User <someuser@widget.com>
-To: "monitor-list@widget.com" <monitor-list@widget.com>
-Sender: "monitor-list-bounces@widget.com" <monitor-list-bounces@widget.com>
-Date: Thu, 19 Mar 2009 13:42:25 -0700
-Subject: Looking for a mac
-Thread-Topic: Looking for a mac
-Thread-Index: AQHJqNM1xIqqjNRWuUCUBaxzPFK5eQ==
-Message-ID:
- <D3C12B2AD838B44DA9D6B2CA334246D011E72A73A4@PA-EXMBX04.widget.com>
-List-Help: <mailto:monitor-list-request@widget.com?subject=help>
-List-Subscribe: <http://mailman2.widget.com/mailman/listinfo/monitor-list>,
-	<mailto:monitor-list-request@widget.com?subject=subscribe>
-List-Unsubscribe:
- <http://mailman2.widget.com/mailman/listinfo/monitor-list>,
- 	<mailto:monitor-list-request@widget.com?subject=unsubscribe>
-Accept-Language: en-US
-Content-Language: en-US
-X-MS-Exchange-Organization-AuthAs: Anonymous
-X-MS-Exchange-Organization-AuthSource: pa-exht01.widget.com
-X-MS-Has-Attach:
-X-Auto-Response-Suppress: All
-X-MS-TNEF-Correlator:
-acceptlanguage: en-US
-delivered-to: monitor-list@widget.com
-errors-to: monitor-list-bounces@widget.com
-list-id: engineering monitor related <monitor-list.widget.com>
-x-mailman-version: 2.1.8
-x-beenthere: monitor-list@widget.com
-x-original-to: monitor-list@mailman2.widget.com
-list-post: <mailto:monitor-list@widget.com>
-list-archive: <http://mailman2.widget.com/pipermail/monitor-list>
-Content-Type: text/plain; charset="us-ascii"
-Content-Transfer-Encoding: quoted-printable
-
-Hi all,
-
-    Just wondering if anybody can lend me a mac to reproduce PR 384931 ?
-    Thanks.
-
-Michael=
-EOS
+    message = fixture('blank-header-fields.eml')
 
     source = DummySource.new("sup-test://test_blank_header_lines")
     source.messages = [ message ]
@@ -496,72 +197,14 @@ EOS
 
     # Look at another header field whose first line was blank.
     list_unsubscribe = sup_message.list_unsubscribe
-    assert_equal("<http://mailman2.widget.com/mailman/listinfo/monitor-list>,\n \t" +
+    assert_equal("<http://mailman2.widget.com/mailman/listinfo/monitor-list>,\n\t" +
                  "<mailto:monitor-list-request@widget.com?subject=unsubscribe>",
                  list_unsubscribe)
 
   end
 
   def test_malicious_attachment_names
-
-
-    message = <<EOS
-From: Matthieu Rakotojaona <matthieu.rakotojaona@gmail.com>
-To: reply+0007a7cb7174d1d188fcd420fce83e0f68fe03fc7416cdae92cf0000000110ce4efd92a169ce033d18e1 <reply+0007a7cb7174d1d188fcd420fce83e0f68fe03fc7416cdae92cf0000000110ce4efd92a169ce033d18e1@reply.github.com>
-Subject: Re: [sup] Attachment saving and special characters in filenames (#378)
-In-reply-to: <sup-heliotrope/sup/issues/378@github.com>
-References: <sup-heliotrope/sup/issues/378@github.com>
-X-pgp-key: http://otokar.looc2011.eu/static/matthieu.rakotojaona.asc
-Date: Wed, 14 Jan 2015 22:13:37 +0100
-Message-Id: <1421269972-sup-5245@kpad>
-User-Agent: Sup/git
-Content-Transfer-Encoding: 8bit
-MIME-Version: 1.0
-Content-Type: multipart/mixed; boundary="=-1421270017-526778-1064-1628-1-="
-
-
---=-1421270017-526778-1064-1628-1-=
-Content-Type: text/plain; charset=UTF-8
-Content-Disposition: inline
-
-Excerpts from Felix Kaiser's message of 2015-01-14 16:36:29 +0100:
-> When saving attachments, sup should replace special characters when suggesting a filename to save the attachment to.
-> 
-> I just got an attachment with a name like "foo/2.pdf". sup suggests saving it to /home/fxkr/foo/2.pdf (and fails to save it, of course, if /home/fxkr/foo isn't a directory).
-> 
-> I haven't tested the "Save All" feature, but I hope nothing bad happens when there's an attachment called "../../../../../../../home/fxkr/.bashrc" ;-)
-> 
-> ---
-> Reply to this email directly or view it on GitHub:
-> https://github.com/sup-heliotrope/sup/issues/378
-
-For tests, here's an email with an attachment filename set to
-sup/.travis.yml (really, this time)
-
--- 
-Matthieu Rakotojaona
-
---=-1421270017-526778-1064-1628-1-=
-Content-Disposition: attachment; filename="sup/.travis.yml"
-Content-Type: text/x-yaml; name="sup/.travis.yml"
-Content-Transfer-Encoding: 8bit
-
-language: ruby
-
-rvm:
-  - 2.1.1
-  - 2.0.0
-  - 1.9.3
-
-before_install:
-  - sudo apt-get update -qq
-  - sudo apt-get install -qq uuid-dev uuid libncursesw5-dev libncursesw5 gnupg2 pandoc
-  - git submodule update --init --recursive
-
-script: bundle exec rake travis
-
---=-1421270017-526778-1064-1628-1-=--
-EOS
+    message = fixture('malicious-attachment-names.eml')
 
     source = DummySource.new("sup-test://test_blank_header_lines")
     source.messages = [ message ]
@@ -576,7 +219,6 @@ EOS
     # path.
     fn = chunks[3].safe_filename
     assert_equal(fn, File.basename(fn))
-
   end
   # TODO: test different error cases, malformed messages etc.
 
diff --git a/test/test_messages_dir.rb b/test/test_messages_dir.rb
@@ -22,9 +22,7 @@ class TestMessagesDir < ::Minitest::Test
 
   def test_binary_content_transfer_encoding
     message = ''
-    File.open 'test/messages/binary-content-transfer-encoding-2.eml' do |f|
-      message = f.read
-    end
+    File.open('test/fixtures/binary-content-transfer-encoding-2.eml') { |f| message = f.read }
 
     source = DummySource.new("sup-test://test_messages")
     source.messages = [ message ]
@@ -56,9 +54,7 @@ class TestMessagesDir < ::Minitest::Test
 
   def test_bad_content_transfer_encoding
     message = ''
-    File.open 'test/messages/bad-content-transfer-encoding-1.eml' do |f|
-      message = f.read
-    end
+    File.open('test/fixtures/bad-content-transfer-encoding-1.eml') { |f| message = f.read }
 
     source = DummySource.new("sup-test://test_messages")
     source.messages = [ message ]
@@ -90,9 +86,7 @@ class TestMessagesDir < ::Minitest::Test
 
   def test_missing_line
     message = ''
-    File.open 'test/messages/missing-line.eml' do |f|
-      message = f.read
-    end
+    File.open('test/fixtures/missing-line.eml') { |f| message = f.read }
 
     source = DummySource.new("sup-test://test_messages")
     source.messages = [ message ]
diff --git a/test/unit/test_contact.rb b/test/unit/test_contact.rb
@@ -5,7 +5,7 @@ module Redwood
 
 class TestContact < Minitest::Test
   def setup
-    @contact = ContactManager.init(File.expand_path("../fixtures/contacts.txt", __FILE__))
+    @contact = ContactManager.init(File.expand_path("../../fixtures/contacts.txt", __FILE__))
     @person  = Person.new "Terrible Name", "terrible@name.com"
   end