github.com/biogo/biogo@v1.0.4/seq/sequtils/utils_test.go (about)

     1  // Copyright ©2011-2012 The bíogo Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sequtils
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"testing"
    11  
    12  	"github.com/biogo/biogo/alphabet"
    13  	"github.com/biogo/biogo/feat"
    14  	"github.com/biogo/biogo/seq"
    15  	"gopkg.in/check.v1"
    16  )
    17  
    18  // Tests
    19  func Test(t *testing.T) { check.TestingT(t) }
    20  
    21  type S struct{}
    22  
    23  var _ = check.Suite(&S{})
    24  
    25  var (
    26  	lorem = stringToSlice("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
    27  )
    28  
    29  type slice []byte
    30  
    31  func stringToSlice(s string) slice {
    32  	return []byte(s)
    33  }
    34  func (s slice) Make(len, cap int) alphabet.Slice       { return make(slice, len, cap) }
    35  func (s slice) Len() int                               { return len(s) }
    36  func (s slice) Cap() int                               { return cap(s) }
    37  func (s slice) Slice(start, end int) alphabet.Slice    { return s[start:end] }
    38  func (s slice) Append(a alphabet.Slice) alphabet.Slice { return append(s, a.(slice)...) }
    39  func (s slice) Copy(a alphabet.Slice) int              { return copy(s, a.(slice)) }
    40  
    41  type offSlice struct {
    42  	slice
    43  	offset int
    44  	conf   feat.Conformation
    45  }
    46  
    47  func stringToOffSlice(s string) *offSlice {
    48  	return &offSlice{slice: stringToSlice(s)}
    49  }
    50  func (os *offSlice) Conformation() feat.Conformation { return os.conf }
    51  func (os *offSlice) SetOffset(o int) error           { os.offset = o; return nil }
    52  func (os *offSlice) Slice() alphabet.Slice           { return os.slice }
    53  func (os *offSlice) SetSlice(sl alphabet.Slice)      { os.slice = sl.(slice) }
    54  func (os *offSlice) String() string                  { return fmt.Sprintf("%s %d", os.slice, os.offset) }
    55  
    56  type conformRangeOffSlice struct {
    57  	slice
    58  	offset int
    59  	conf   feat.Conformation
    60  }
    61  
    62  func stringToConformRangeOffSlice(s string) *conformRangeOffSlice {
    63  	return &conformRangeOffSlice{slice: stringToSlice(s)}
    64  }
    65  func (os *conformRangeOffSlice) Conformation() feat.Conformation     { return os.conf }
    66  func (os *conformRangeOffSlice) SetConformation(c feat.Conformation) { os.conf = c }
    67  func (os *conformRangeOffSlice) SetOffset(o int) error               { os.offset = o; return nil }
    68  func (os *conformRangeOffSlice) Start() int                          { return os.offset }
    69  func (os *conformRangeOffSlice) End() int                            { return os.offset + len(os.slice) }
    70  func (os *conformRangeOffSlice) Slice() alphabet.Slice               { return os.slice }
    71  func (os *conformRangeOffSlice) SetSlice(sl alphabet.Slice)          { os.slice = sl.(slice) }
    72  func (os *conformRangeOffSlice) String() string                      { return fmt.Sprintf("%s", os.slice) }
    73  
    74  func (s *S) TestTruncate(c *check.C) {
    75  	type test struct {
    76  		in         *conformRangeOffSlice
    77  		start, end int
    78  		expect     interface{}
    79  	}
    80  
    81  	var T []test = []test{
    82  		{
    83  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
    84  			start:  28,
    85  			end:    39,
    86  			expect: stringToSlice("consectetur"),
    87  		},
    88  		{
    89  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 1},
    90  			start:  29,
    91  			end:    40,
    92  			expect: stringToSlice("consectetur"),
    93  		},
    94  		{
    95  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
    96  			start:  28,
    97  			end:    39,
    98  			expect: stringToSlice("consectetur"),
    99  		},
   100  		{
   101  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
   102  			start:  117,
   103  			end:    5,
   104  			expect: "sequtils: start position greater than end position for linear sequence",
   105  		},
   106  		{
   107  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
   108  			start:  117,
   109  			end:    5,
   110  			expect: stringToSlice("aliqua.Lorem"),
   111  		},
   112  		{
   113  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular, offset: 1},
   114  			start:  118,
   115  			end:    6,
   116  			expect: stringToSlice("aliqua.Lorem"),
   117  		},
   118  		{
   119  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear},
   120  			start:  5,
   121  			end:    1170,
   122  			expect: "sequtils: index out of range",
   123  		},
   124  		{
   125  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Circular},
   126  			start:  1170,
   127  			end:    5,
   128  			expect: "sequtils: index out of range",
   129  		},
   130  	}
   131  
   132  	for _, t := range T {
   133  		r := &conformRangeOffSlice{}
   134  		if err := Truncate(r, t.in, t.start, t.end); err != nil {
   135  			c.Check(err, check.ErrorMatches, t.expect)
   136  		} else {
   137  			c.Check(r.slice, check.DeepEquals, t.expect)
   138  			c.Check(r.conf, check.Equals, feat.Linear)
   139  			if t.in.conf != feat.Circular || (t.in.conf == feat.Circular && t.end >= t.start) {
   140  				c.Check(t.end-t.start, check.Equals, reflect.ValueOf(t.expect).Len())
   141  			} else {
   142  				c.Check(t.end+reflect.ValueOf(t.in.slice).Len()-t.start, check.Equals, reflect.ValueOf(t.expect).Len())
   143  			}
   144  		}
   145  	}
   146  }
   147  
   148  func (s *S) TestJoin(c *check.C) {
   149  	type test struct {
   150  		a, b   *offSlice
   151  		where  int
   152  		expect *offSlice
   153  	}
   154  
   155  	var T []test = []test{
   156  		{
   157  			a:      &offSlice{lorem[28:40], 0, feat.Linear},
   158  			b:      &offSlice{lorem[117:], 0, feat.Linear},
   159  			where:  seq.Start,
   160  			expect: &offSlice{stringToSlice("aliqua.consectetur "), -7, feat.Linear},
   161  		},
   162  		{
   163  			a:      &offSlice{lorem[28:40], 0, feat.Linear},
   164  			b:      &offSlice{lorem[117:], 0, feat.Linear},
   165  			where:  seq.End,
   166  			expect: &offSlice{stringToSlice("consectetur aliqua."), 0, feat.Linear},
   167  		},
   168  	}
   169  
   170  	for _, t := range T {
   171  		Join(t.a, t.b, t.where)
   172  		c.Check(t.a, check.DeepEquals, t.expect)
   173  	}
   174  }
   175  
   176  type fe struct {
   177  	s, e   int
   178  	orient feat.Orientation
   179  	feat.Feature
   180  }
   181  
   182  func (f fe) Start() int                    { return f.s }
   183  func (f fe) End() int                      { return f.e }
   184  func (f fe) Len() int                      { return f.e - f.s }
   185  func (f fe) Orientation() feat.Orientation { return f.orient }
   186  
   187  type fs []feat.Feature
   188  
   189  func (f fs) Features() []feat.Feature { return []feat.Feature(f) }
   190  
   191  func (s *S) TestStitch(c *check.C) {
   192  	type test struct {
   193  		in     *conformRangeOffSlice
   194  		f      feat.Set
   195  		expect interface{}
   196  	}
   197  
   198  	var T []test = []test{
   199  		{
   200  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
   201  			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
   202  			expect: stringToSlice("dolor et dolore"),
   203  		},
   204  		{
   205  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
   206  			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
   207  			expect: stringToSlice("olor st,dolore "),
   208  		},
   209  		{
   210  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
   211  			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
   212  			expect: stringToSlice("dolor et dolore"),
   213  		},
   214  		{
   215  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
   216  			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
   217  			expect: stringToSlice("olor st,dolore "),
   218  		},
   219  		{
   220  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
   221  			f:      fs{fe{s: 19, e: 18}},
   222  			expect: "sequtils: feature end < feature start",
   223  		},
   224  	}
   225  
   226  	for _, t := range T {
   227  		r := &conformRangeOffSlice{}
   228  		if err := Stitch(r, t.in, t.f); err != nil {
   229  			c.Check(err, check.ErrorMatches, t.expect)
   230  		} else {
   231  			c.Check(r.slice, check.DeepEquals, t.expect)
   232  		}
   233  	}
   234  }
   235  
   236  func (s *S) TestCompose(c *check.C) {
   237  	type test struct {
   238  		in     *conformRangeOffSlice
   239  		f      feat.Set
   240  		expect interface{}
   241  	}
   242  
   243  	var T []test = []test{
   244  		{
   245  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
   246  			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
   247  			expect: stringToSlice("dolor et dolore"),
   248  		},
   249  		{
   250  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
   251  			f:      fs{fe{s: 12, e: 18}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
   252  			expect: stringToSlice("olor st,dolore "),
   253  		},
   254  		{
   255  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
   256  			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
   257  			expect: stringToSlice("dolor oloret dolore"),
   258  		},
   259  		{
   260  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
   261  			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26}, fe{s: 103, e: 110}},
   262  			expect: stringToSlice("olor slor t,dolore "),
   263  		},
   264  		{
   265  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: -1},
   266  			f:      fs{fe{s: 12, e: 18}, fe{s: 13, e: 17}, fe{s: 24, e: 26, orient: feat.Reverse}, fe{s: 103, e: 110}},
   267  			expect: "sequtils: unable to reverse segment during compose",
   268  		},
   269  		{
   270  			in:     &conformRangeOffSlice{slice: lorem, conf: feat.Linear, offset: 0},
   271  			f:      fs{fe{s: 19, e: 18}},
   272  			expect: "sequtils: feature end < feature start",
   273  		},
   274  	}
   275  
   276  	for _, t := range T {
   277  		r := &conformRangeOffSlice{}
   278  		if err := Compose(r, t.in, t.f); err == nil {
   279  			c.Check(r.slice, check.DeepEquals, t.expect)
   280  		} else {
   281  			c.Check(err, check.ErrorMatches, t.expect)
   282  		}
   283  	}
   284  }