Update mussa to build on ubuntu 10.04 with qt 4.6.2 +boost 1.40.0.1
[mussa.git] / alg / test / test_mussa.cpp
index bebb38d2548e2cec34b43d642ac73c33627ec413..5255fe26d7a309130c99b0369bbb8749fba7298a 100644 (file)
@@ -1,4 +1,7 @@
-#include <boost/test/auto_unit_test.hpp>
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE test_mussa
+#include <boost/test/unit_test.hpp>
+
 #include <boost/filesystem/path.hpp>
 #include <boost/filesystem/operations.hpp>
 namespace fs = boost::filesystem;
@@ -50,6 +53,20 @@ BOOST_AUTO_TEST_CASE( mussa_simple )
   BOOST_CHECK_EQUAL(m.get_analysis_mode(), Mussa::TransitiveNway);
 }
 
+BOOST_AUTO_TEST_CASE ( mussa_title )
+{
+  Mussa m;
+  
+  BOOST_CHECK_EQUAL( m.get_title(), "Unnamed");
+  string foo("foo");
+  m.set_name(foo);
+  BOOST_CHECK_EQUAL( m.get_title(), foo);
+  string foopath_name("/my/silly/path");
+  fs::path foopath(foopath_name);
+  m.set_analysis_path(foopath);
+  BOOST_CHECK_EQUAL( m.get_title().size(), 14);
+}
+
 BOOST_AUTO_TEST_CASE( mussa_analysis_name )
 {
   Mussa m;
@@ -95,6 +112,58 @@ BOOST_AUTO_TEST_CASE ( empty_mussa_set_threshold )
   m.nway();
 }
 
+BOOST_AUTO_TEST_CASE( mussa_load_mupa_crlf )
+{
+  fs::path example_path(EXAMPLE_DIR, fs::native);
+  fs::path seq_path(example_path / "seq" / "mouse_mck_pro.fa");
+  fs::path annot_path(example_path / "mm_mck3test.annot");
+
+  std::string mupa(
+    "# hello\015\012"
+    "ANA_NAME load_mupa_crlf\015\012");
+  mupa += "SEQUENCE " + seq_path.native_file_string() + "\015\012";
+  mupa += "ANNOTATION " + annot_path.native_file_string() + "\015\012";
+  
+  istringstream mupa_stream(mupa);
+  Mussa m;
+  fs::path base;
+  m.load_mupa_stream( mupa_stream, base );
+  // Should run with no exceptions
+}
+
+BOOST_AUTO_TEST_CASE( mussa_load_mupa_comment_character )
+{
+  fs::path mupa_path(EXAMPLE_DIR, fs::native);
+  fs::path seq_path = fs::initial_path() / "seq" / "mouse_mck_pro.fa";
+  fs::path annot_path = fs::initial_path() / "mm_mck3test.annot";
+
+  std::string mupa(
+    "# hello\015\012"
+    "ANA_NAME load_mupa_crlf\015\012");
+  mupa += "#SEQUENCE " + seq_path.native_file_string() + "\015\012";
+  mupa += "#ANNOTATION " + annot_path.native_file_string() + "\015\012";
+  
+  istringstream mupa_stream(mupa);
+  Mussa m;
+  fs::path base;
+  m.load_mupa_stream( mupa_stream, base );
+  // Should run with no exceptions
+}
+
+BOOST_AUTO_TEST_CASE( mussa_load_mupa_exception )
+{
+  std::string mupa(
+    "# hello\015\012"
+    "ANA_NAME load_mupa_crlf\015\012"
+    "mwahhaha I broke you!\n"
+  );
+  
+  istringstream mupa_stream(mupa);
+  Mussa m;
+  fs::path base;
+  BOOST_CHECK_THROW(m.load_mupa_stream( mupa_stream, base ), mussa_load_error);
+}
+
 BOOST_AUTO_TEST_CASE( mussa_load_mupa )
 {
   fs::path mupa_path(EXAMPLE_DIR, fs::native);
@@ -137,6 +206,17 @@ BOOST_AUTO_TEST_CASE( mussa_load_full_path )
   BOOST_CHECK_EQUAL( m1.is_dirty(), true);
   BOOST_CHECK_EQUAL( m1.get_analysis_path().string(), "");
 }
+  
+BOOST_AUTO_TEST_CASE( mussa_valid_motifs_in_new_analysis )
+{
+  Mussa m1;
+  fs::path full_path(fs::path(EXAMPLE_DIR, fs::native) / "mck3test.mupa");
+  m1.load_mupa_file( full_path );
+  m1.analyze();
+  // check motifs
+  BOOST_CHECK( m1.sequences().size() > 0 );
+  BOOST_CHECK_EQUAL( m1.sequences()[0]->motifs().size(), 0 );  
+}
 
 // make sure we know that mupa files cannot be directories 
 BOOST_AUTO_TEST_CASE( mussa_mupa_is_file_not_directory )
@@ -146,6 +226,14 @@ BOOST_AUTO_TEST_CASE( mussa_mupa_is_file_not_directory )
   BOOST_CHECK_THROW(m1.load_mupa_file( curdir ), mussa_load_error );
 }
 
+// catch error if annotation isn't a file
+BOOST_AUTO_TEST_CASE( mussa_annotation_is_not_file )
+{
+  Mussa m1;
+  fs::path full_path(fs::path(EXAMPLE_DIR, fs::native) / "directory.mupa");
+  BOOST_CHECK_THROW( m1.load_mupa_file( full_path ), mussa_load_error );
+}
+
 BOOST_AUTO_TEST_CASE( mussa_load_analysis )
 {
   fs::path example_dir(EXAMPLE_DIR, fs::native);
@@ -166,8 +254,7 @@ BOOST_AUTO_TEST_CASE( mussa_load_analysis )
 BOOST_AUTO_TEST_CASE( mussa_load_motif )
 {
   string data = "AAGG 1.0 1.0 0.0\n"
-                "GGTT 0.0 0.1 1.0\n"
-                "ZXY 2 1.9 0\n";
+                "GGTT 0.0 0.1 1.0 1.0\n";
 
   istringstream test_istream(data);
 
@@ -176,6 +263,7 @@ BOOST_AUTO_TEST_CASE( mussa_load_motif )
   m1.append_sequence("GGGCCCCTTCCAATT");
   m1.load_motifs(test_istream);
 
+  BOOST_CHECK_EQUAL( m1.motifs().size(), 2);
   for (Mussa::vector_sequence_type::const_iterator seq_i = m1.sequences().begin();
        seq_i != m1.sequences().end();
        ++seq_i)
@@ -184,6 +272,22 @@ BOOST_AUTO_TEST_CASE( mussa_load_motif )
   }
 }
 
+BOOST_AUTO_TEST_CASE( mussa_load_broken_motif )
+{
+  string data = "AAGG 1.0 1.0 0.0\n"
+                "GGTT 0.0 0.1 1.0 1.0\n"
+                "ZZCTA 0.1 0.0 1.0\n";
+
+  istringstream test_istream(data);
+
+  Mussa m1;
+  m1.append_sequence("AAAAGGGGTTTT");
+  m1.append_sequence("GGGCCCCTTCCAATT");
+  BOOST_CHECK_THROW(m1.load_motifs(test_istream), motif_load_error);
+
+  BOOST_CHECK_EQUAL( m1.motifs().size(), 0);
+}
+
 BOOST_AUTO_TEST_CASE( mussa_named_motif )
 {
   string data = "CCAATT cat 0.1 0.2 0.3\n";
@@ -199,6 +303,88 @@ BOOST_AUTO_TEST_CASE( mussa_named_motif )
   BOOST_CHECK_EQUAL(motifs.begin()->get_name(), "cat");
 }
 
+BOOST_AUTO_TEST_CASE( mussa_weirdly_spaced_named_motif )
+{
+  string data = "CCAATT       cat_meow123     0.1    0.2 0.3\n";
+  istringstream test_istream(data);
+
+  Mussa m1;
+  m1.append_sequence("AAAAGGGGTTTT");
+  m1.append_sequence("GGGCCCCTTCCAATT");
+  m1.load_motifs(test_istream);
+
+  std::set<Sequence> motifs = m1.motifs();
+  BOOST_REQUIRE_EQUAL(motifs.size(), 1);
+  BOOST_CHECK_EQUAL(motifs.begin()->get_name(), "cat_meow123");
+}
+
+BOOST_AUTO_TEST_CASE( mussa_name_quoted_motif )
+{
+  string data = "CCAATT       \"cat meow 123\"     0.1    0.2 0.3\n";
+  istringstream test_istream(data);
+
+  Mussa m1;
+  m1.append_sequence("AAAAGGGGTTTT");
+  m1.append_sequence("GGGCCCCTTCCAATT");
+  m1.load_motifs(test_istream);
+
+  std::set<Sequence> motifs = m1.motifs();
+  BOOST_REQUIRE_EQUAL(motifs.size(), 1);
+  BOOST_CHECK_EQUAL(motifs.begin()->get_name(), "cat meow 123");
+}
+
+BOOST_AUTO_TEST_CASE( mussa_name_embedded_quote_motif )
+{
+  // pretty obviously this shouldn't work as " are our delimiter
+  // and i'm too lazy to add support for \ in the parser
+  string data = "ATA 0.5 0.5 0.5\n"
+                "CCAATT       \"cat \"meow 123\"     0.1    0.2 0.3\n";
+  istringstream test_istream(data);
+
+  Mussa m1;
+  m1.append_sequence("AAAAGGGGTTTT");
+  m1.append_sequence("GGGCCCCTTCCAATT");
+  BOOST_CHECK_THROW( m1.load_motifs(test_istream), motif_load_error);
+
+  std::set<Sequence> motifs = m1.motifs();
+  BOOST_REQUIRE_EQUAL(motifs.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE( mussa_save_motif )
+{
+  string data = "ATA 1 1 1 1\n"
+                "CAT \"my name\" 1 0 0.5 0.5\n";
+  istringstream data_istream(data);
+
+  Mussa m1;
+  m1.append_sequence("AAAAGGGGTTTT");
+  m1.append_sequence("GGGCCCCTTCCAATT");
+  m1.load_motifs(data_istream);
+  
+  string save;
+  ostringstream save_ostream(save);
+  m1.save_motifs(save_ostream);
+
+  istringstream reloaded_istream(save_ostream.str());
+  Mussa m2;
+  m2.append_sequence("AAAAGGGGTTTT");
+  m2.append_sequence("GGGCCCCTTCCAATT");
+  m2.load_motifs(reloaded_istream);
+  
+  BOOST_REQUIRE_EQUAL(m1.motifs().size(), m2.motifs().size());
+  Mussa::motif_set::const_iterator m1motif = m1.motifs().begin();
+  Mussa::motif_set::const_iterator m2motif = m2.motifs().begin();
+  for (;
+       m1motif != m1.motifs().end() and m2motif != m2.motifs().end();
+       ++m1motif, ++m2motif) 
+  {
+    BOOST_CHECK_EQUAL(m1motif->get_sequence(), m2motif->get_sequence());
+    BOOST_CHECK_EQUAL(m1motif->get_name(), m2motif->get_name());
+    BOOST_CHECK_EQUAL(m1.colorMapper()->lookup("motif", m1motif->get_sequence()),
+                      m2.colorMapper()->lookup("motif", m2motif->get_sequence()));
+  }  
+}
+
 BOOST_AUTO_TEST_CASE( mussa_add_motif )
 {
   vector<Sequence> motifs;
@@ -248,9 +434,9 @@ BOOST_AUTO_TEST_CASE( mussa_add_motif )
 }
 
 static void 
-local_align_test(const Mussa::vector_sequence_type &seqs, 
-                 const list<ConservedPath::path_type>& result,
-                 const list<vector<bool> >& reversed)
+two_way_local_align_test(const Mussa::vector_sequence_type &seqs, 
+                         const list<ConservedPath::path_type>& result,
+                         const list<vector<bool> >& reversed)
 {
   map<char, vector <char> >  m;
   assign::insert(m)('A', assign::list_of('A')('T') )
@@ -278,9 +464,8 @@ local_align_test(const Mussa::vector_sequence_type &seqs,
     BOOST_CHECK_EQUAL( first_basepair, complimented_second) ;
   }
 }
-
                  
-BOOST_AUTO_TEST_CASE( local_alignment )
+BOOST_AUTO_TEST_CASE( two_way_local_alignment )
 {
   string s0("GCGCATAT");
   string s1("AAAAAAAT");
@@ -293,6 +478,8 @@ BOOST_AUTO_TEST_CASE( local_alignment )
   analysis.set_window(4);
   analysis.analyze();
   NwayPaths npath = analysis.paths();
+  BOOST_REQUIRE_EQUAL( npath.pathz.size(), 2 );
+  
   list<ConservedPath::path_type> result;
   list<vector<bool> > reversed;
   list<ConservedPath>::iterator pathz_i = npath.pathz.begin();
@@ -304,7 +491,7 @@ BOOST_AUTO_TEST_CASE( local_alignment )
                                 result,
                                 reversed);
 
-  local_align_test(analysis.sequences(), result, reversed);
+  two_way_local_align_test(analysis.sequences(), result, reversed);
 
   ++pathz_i;
   result.clear();
@@ -315,9 +502,64 @@ BOOST_AUTO_TEST_CASE( local_alignment )
                                 selected_paths.end(),
                                 result,
                                 reversed);
-  local_align_test(analysis.sequences(), result, reversed);
+  two_way_local_align_test(analysis.sequences(), result, reversed);
+}
 
+BOOST_AUTO_TEST_CASE( three_way_local_alignment )
+{
+  string s0("AGCAGGGAGGGTTTAAATGGCACCCAGCAGTTGGTGTGAGG");
+  string s1("AGCGGGAAGGGTTTAAATGGCACCGGGCAGTTGGCGTGAGG");
+  string s2("CAGCGCCGGGGTTTAAATGGCACCGAGCAGTTGGCGCAGGG");
+  
+  Mussa analysis;
+  analysis.append_sequence(s0);
+  analysis.append_sequence(s1);
+  analysis.append_sequence(s2);
+  analysis.set_threshold(23);
+  analysis.set_window(30);
+  analysis.analyze();
+  NwayPaths npath = analysis.paths();
+  BOOST_CHECK_EQUAL( npath.refined_pathz.size(), 1 );
+  
+  list<ConservedPath::path_type> result;
+  list<vector<bool> > reversed;
+  // grab 1 path (since there's only one)
+  list<ConservedPath>::iterator pathz_i = npath.pathz.begin();
+  list<ConservedPath> selected_paths;
+  selected_paths.push_back(*pathz_i);
+  analysis.createLocalAlignment(selected_paths.begin(), 
+                                selected_paths.end(),
+                                result,
+                                reversed);
+                                
+  for(std::list<ConservedPath::path_type>::iterator result_i = result.begin();
+      result_i != result.end();
+      ++result_i)
+  {
+    ConservedPath::path_element first_element = *(result_i->begin());
+    for (ConservedPath::path_type::iterator element_i = result_i->begin();
+         element_i != result_i->end();
+         ++element_i)
+    {
+      BOOST_CHECK_EQUAL( *element_i, first_element );
+      BOOST_CHECK_EQUAL( s0[*element_i], s1[*element_i] );
+      BOOST_CHECK_EQUAL( s1[*element_i], s2[*element_i] );
+      BOOST_CHECK_EQUAL( s0[*element_i], s2[*element_i] );
+    }
+  }   
+}
 
+BOOST_AUTO_TEST_CASE( mussa_window_larger_than_sequence )
+{
+  string s0("AGCAGGG");
+  string s1("CAGCGGG");
+  
+  Mussa analysis;
+  analysis.append_sequence(s0);
+  analysis.append_sequence(s1);
+  analysis.set_threshold(23);
+  analysis.set_window(30);
+  BOOST_CHECK_THROW(analysis.analyze(), seqcomp_error);
 }
 
 BOOST_AUTO_TEST_CASE( subanalysis )