github.com/biogo/biogo@v1.0.4/feat/feature_test.go (about)

     1  // Copyright ©2011-2013 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 feat_test
     6  
     7  import (
     8  	"github.com/biogo/biogo/feat"
     9  	"github.com/biogo/biogo/seq/alignment"
    10  	"github.com/biogo/biogo/seq/linear"
    11  	"github.com/biogo/biogo/seq/multi"
    12  
    13  	"gopkg.in/check.v1"
    14  )
    15  
    16  var (
    17  	_ feat.Feature = (*linear.Seq)(nil)
    18  	_ feat.Feature = (*linear.QSeq)(nil)
    19  	_ feat.Feature = (*alignment.Seq)(nil)
    20  	_ feat.Feature = (*alignment.QSeq)(nil)
    21  	_ feat.Feature = (*multi.Multi)(nil)
    22  
    23  	_ feat.Offsetter = (*linear.Seq)(nil)
    24  	_ feat.Offsetter = (*linear.QSeq)(nil)
    25  	_ feat.Offsetter = (*alignment.Seq)(nil)
    26  	_ feat.Offsetter = (*alignment.QSeq)(nil)
    27  	_ feat.Offsetter = (*multi.Multi)(nil)
    28  
    29  	_ feat.LocationSetter = (*linear.Seq)(nil)
    30  	_ feat.LocationSetter = (*linear.QSeq)(nil)
    31  	_ feat.LocationSetter = (*alignment.Seq)(nil)
    32  	_ feat.LocationSetter = (*alignment.QSeq)(nil)
    33  	_ feat.LocationSetter = (*multi.Multi)(nil)
    34  )
    35  
    36  type S struct{}
    37  
    38  var _ = check.Suite(&S{})
    39  
    40  type chrom int
    41  
    42  func (c chrom) Name() string           { return "test" }
    43  func (c chrom) Description() string    { return "chromosome" }
    44  func (c chrom) Start() int             { return 0 }
    45  func (c chrom) End() int               { return int(c) }
    46  func (c chrom) Len() int               { return int(c) }
    47  func (c chrom) Location() feat.Feature { return nil }
    48  
    49  type nonOri struct {
    50  	start, end int
    51  	name       string
    52  	desc       string
    53  	loc        feat.Feature
    54  }
    55  
    56  func (o nonOri) Name() string           { return o.name }
    57  func (o nonOri) Description() string    { return o.desc }
    58  func (o nonOri) Start() int             { return o.start }
    59  func (o nonOri) End() int               { return o.end }
    60  func (o nonOri) Len() int               { return o.end - o.start }
    61  func (o nonOri) Location() feat.Feature { return o.loc }
    62  
    63  type ori struct {
    64  	nonOri
    65  	orient feat.Orientation
    66  }
    67  
    68  func (o ori) Orientation() feat.Orientation { return o.orient }
    69  
    70  var (
    71  	chrom1 = chrom(1000)
    72  	chrom2 = chrom(500)
    73  	geneA  = ori{
    74  		nonOri: nonOri{
    75  			start: 10, end: 50,
    76  			name: "genA",
    77  			desc: "gene",
    78  			loc:  chrom1,
    79  		},
    80  		orient: feat.Forward,
    81  	}
    82  	proA = ori{
    83  		nonOri: nonOri{
    84  			start: 10, end: 20,
    85  			name: "genA",
    86  			desc: "promoter",
    87  			loc:  geneA,
    88  		},
    89  		orient: feat.Forward,
    90  	}
    91  	pribA = ori{
    92  		nonOri: nonOri{
    93  			start: 15, end: 20,
    94  			name: "pribA",
    95  			desc: "promoter box",
    96  			loc:  proA,
    97  		},
    98  		orient: feat.Forward,
    99  	}
   100  	opA = nonOri{
   101  		start: 12, end: 16,
   102  		name: "genb",
   103  		desc: "operator",
   104  		loc:  proA,
   105  	}
   106  	orfA = ori{
   107  		nonOri: nonOri{
   108  			start: 15, end: 30,
   109  			name: "genA",
   110  			desc: "orf",
   111  			loc:  geneA,
   112  		},
   113  		orient: feat.Forward,
   114  	}
   115  	antiA = ori{
   116  		nonOri: nonOri{
   117  			start: 45, end: 50,
   118  			name: "genA",
   119  			desc: "antisense",
   120  			loc:  geneA,
   121  		},
   122  		orient: feat.Reverse,
   123  	}
   124  
   125  	geneB = ori{
   126  		nonOri: nonOri{
   127  			start: 60, end: 100,
   128  			name: "genB",
   129  			desc: "gene",
   130  			loc:  chrom1,
   131  		},
   132  		orient: feat.Reverse,
   133  	}
   134  	proB = ori{
   135  		nonOri: nonOri{
   136  			start: 90, end: 100,
   137  			name: "genB",
   138  			desc: "promoter",
   139  			loc:  geneB,
   140  		},
   141  		orient: feat.Forward,
   142  	}
   143  	opB = nonOri{
   144  		start: 94, end: 98,
   145  		name: "genB",
   146  		desc: "operator",
   147  		loc:  proB,
   148  	}
   149  	orfB = ori{
   150  		nonOri: nonOri{
   151  			start: 15, end: 30,
   152  			name: "genb",
   153  			desc: "orf",
   154  			loc:  geneB,
   155  		},
   156  		orient: feat.Forward,
   157  	}
   158  
   159  	pal = nonOri{
   160  		start: 300, end: 320,
   161  		name: "palA",
   162  		desc: "palindrome",
   163  		loc:  chrom1,
   164  	}
   165  
   166  	freeOri1 = ori{
   167  		nonOri: nonOri{
   168  			start: 10, end: 100,
   169  			name: "frag1",
   170  			desc: "fragment",
   171  		},
   172  		orient: feat.Reverse,
   173  	}
   174  
   175  	freeOri2 = ori{
   176  		nonOri: nonOri{
   177  			start: 100, end: 200,
   178  			name: "frag2",
   179  			desc: "fragment",
   180  		},
   181  		orient: feat.Forward,
   182  	}
   183  
   184  	freeOriNotOriented = ori{
   185  		nonOri: nonOri{
   186  			start: 10, end: 100,
   187  			name: "frag",
   188  			desc: "fragment",
   189  		},
   190  		orient: feat.NotOriented,
   191  	}
   192  
   193  	orientationTests = []struct {
   194  		f         feat.Feature
   195  		baseOri   feat.Orientation
   196  		oriWithin feat.Orientation
   197  		ref       feat.Feature
   198  	}{
   199  		{
   200  			f:         chrom1,
   201  			baseOri:   feat.NotOriented,
   202  			oriWithin: feat.NotOriented,
   203  			ref:       chrom1,
   204  		},
   205  		{
   206  			f:         geneA,
   207  			baseOri:   feat.Forward,
   208  			oriWithin: feat.Forward,
   209  			ref:       chrom1,
   210  		},
   211  		{
   212  			f:         orfA,
   213  			baseOri:   feat.Forward,
   214  			oriWithin: feat.Forward,
   215  			ref:       chrom1,
   216  		},
   217  		{
   218  			f:         antiA,
   219  			baseOri:   feat.Reverse,
   220  			oriWithin: feat.Reverse,
   221  			ref:       chrom1,
   222  		},
   223  		{
   224  			f:         proA,
   225  			baseOri:   feat.Forward,
   226  			oriWithin: feat.Forward,
   227  			ref:       chrom1,
   228  		},
   229  		{
   230  			f:         opA,
   231  			baseOri:   feat.NotOriented,
   232  			oriWithin: feat.NotOriented,
   233  			ref:       proA,
   234  		},
   235  		{
   236  			f:         geneB,
   237  			baseOri:   feat.Reverse,
   238  			oriWithin: feat.Reverse,
   239  			ref:       chrom1,
   240  		},
   241  		{
   242  			f:         orfB,
   243  			baseOri:   feat.Reverse,
   244  			oriWithin: feat.Reverse,
   245  			ref:       chrom1,
   246  		},
   247  		{
   248  			f:         proB,
   249  			baseOri:   feat.Reverse,
   250  			oriWithin: feat.Reverse,
   251  			ref:       chrom1,
   252  		},
   253  		{
   254  			f:         opB,
   255  			baseOri:   feat.NotOriented,
   256  			oriWithin: feat.NotOriented,
   257  			ref:       proB,
   258  		},
   259  		{
   260  			f:         pal,
   261  			baseOri:   feat.NotOriented,
   262  			oriWithin: feat.NotOriented,
   263  			ref:       chrom1,
   264  		},
   265  		{
   266  			f:         freeOri1,
   267  			baseOri:   feat.Reverse,
   268  			oriWithin: feat.Forward,
   269  			ref:       freeOri1,
   270  		},
   271  		{
   272  			f:         freeOriNotOriented,
   273  			baseOri:   feat.NotOriented,
   274  			oriWithin: feat.NotOriented,
   275  			ref:       freeOriNotOriented,
   276  		},
   277  	}
   278  )
   279  
   280  func (s *S) TestBaseOrientationOf(c *check.C) {
   281  	for _, t := range orientationTests {
   282  		ori, ref := feat.BaseOrientationOf(t.f)
   283  		c.Check(ori, check.Equals, t.baseOri)
   284  		c.Check(ref, check.Equals, t.ref)
   285  	}
   286  
   287  	// Check that we find the same reference where possible.
   288  	_, ref1 := feat.BaseOrientationOf(orfA)
   289  	_, ref2 := feat.BaseOrientationOf(antiA)
   290  	c.Check(ref1, check.Equals, ref2)
   291  	_, ref1 = feat.BaseOrientationOf(orfA)
   292  	_, ref2 = feat.BaseOrientationOf(orfB)
   293  	c.Check(ref1, check.Equals, ref2)
   294  	_, ref1 = feat.BaseOrientationOf(freeOri1)
   295  	_, ref2 = feat.BaseOrientationOf(freeOri2)
   296  	c.Check(ref1, check.Not(check.Equals), ref2)
   297  
   298  	// Check we detect cycles.
   299  	var cycle ori
   300  	cycle.orient = feat.Forward
   301  	cycle.loc = &cycle
   302  	c.Check(func() { feat.BaseOrientationOf(cycle) }, check.Panics, "feat: feature chain too long")
   303  }
   304  
   305  func (s *S) TestOrientationWithin(c *check.C) {
   306  	for _, t := range orientationTests {
   307  		c.Check(feat.OrientationWithin(t.f, t.ref), check.Equals, t.oriWithin)
   308  	}
   309  
   310  	// Check that a nil reference, an unorientable f or an f not located on
   311  	// reference return NotOriented.
   312  	c.Check(feat.OrientationWithin(freeOri1, nil), check.Equals, feat.NotOriented)
   313  	c.Check(feat.OrientationWithin(pribA, nil), check.Equals, feat.NotOriented)
   314  	c.Check(feat.OrientationWithin(opA, chrom2), check.Equals, feat.NotOriented)
   315  	c.Check(feat.OrientationWithin(opA, geneB), check.Equals, feat.NotOriented)
   316  	c.Check(feat.OrientationWithin(geneA, chrom2), check.Equals, feat.NotOriented)
   317  
   318  	// Check we detect cycles.
   319  	var cycle ori
   320  	cycle.orient = feat.Forward
   321  	cycle.loc = &cycle
   322  	c.Check(func() { feat.OrientationWithin(cycle, chrom1) }, check.Panics, "feat: feature chain too long")
   323  }
   324  
   325  // Tests for BasePositionOf and PositionWithin.
   326  var baseCoordsTests = []struct {
   327  	f, ref                  feat.Feature
   328  	pos, basePos, posWithin int
   329  }{
   330  	{
   331  		f:         chrom1,
   332  		pos:       20,
   333  		basePos:   20,
   334  		posWithin: 20,
   335  		ref:       chrom1,
   336  	},
   337  	{
   338  		f:         geneA,
   339  		pos:       30,
   340  		basePos:   40,
   341  		posWithin: 40,
   342  		ref:       chrom1,
   343  	},
   344  	{
   345  		f:         proA,
   346  		pos:       40,
   347  		basePos:   60,
   348  		posWithin: 60,
   349  		ref:       chrom1,
   350  	},
   351  	{
   352  		f:         opA,
   353  		pos:       20,
   354  		basePos:   52,
   355  		posWithin: 52,
   356  		ref:       chrom1,
   357  	},
   358  	{
   359  		f:         antiA,
   360  		pos:       20,
   361  		basePos:   75,
   362  		posWithin: 75,
   363  		ref:       chrom1,
   364  	},
   365  	{
   366  		f:         freeOri1,
   367  		pos:       0,
   368  		basePos:   10,
   369  		posWithin: 0,
   370  		ref:       freeOri1,
   371  	},
   372  }
   373  
   374  func (s *S) TestBasePositionOf(c *check.C) {
   375  	for _, t := range baseCoordsTests {
   376  		pos, ref := feat.BasePositionOf(t.f, t.pos)
   377  		c.Check(pos, check.Equals, t.basePos)
   378  		c.Check(ref, check.Equals, t.ref)
   379  	}
   380  
   381  	// Check that we find the same reference where possible.
   382  	_, refGeneA := feat.BasePositionOf(geneA, 0)
   383  	_, refGeneB := feat.BasePositionOf(geneB, 0)
   384  	c.Check(refGeneA, check.Equals, refGeneB)
   385  
   386  	// Check we detect cycles.
   387  	var cycle ori
   388  	cycle.loc = &cycle
   389  	c.Check(func() { feat.BasePositionOf(cycle, 10) }, check.Panics, "feat: feature chain too long")
   390  }
   391  
   392  func (s *S) TestPositionWithin(c *check.C) {
   393  	for _, t := range baseCoordsTests {
   394  		pos, ok := feat.PositionWithin(t.f, t.ref, t.pos)
   395  		c.Check(pos, check.Equals, t.posWithin)
   396  		c.Check(ok, check.Equals, true)
   397  	}
   398  
   399  	// Check unorthodox tree structures.
   400  	_, ok := feat.PositionWithin(opA, chrom2, 10)
   401  	c.Check(ok, check.Equals, false)
   402  	_, ok = feat.PositionWithin(opA, nil, 10)
   403  	c.Check(ok, check.Equals, false)
   404  	_, ok = feat.PositionWithin(nil, nil, 10)
   405  	c.Check(ok, check.Equals, false)
   406  
   407  	// Check we detect cycles.
   408  	var cycle ori
   409  	cycle.loc = &cycle
   410  	c.Check(func() { feat.PositionWithin(cycle, chrom1, 10) }, check.Panics, "feat: feature chain too long")
   411  }