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 }