github.com/Schaudge/hts@v0.0.0-20240223063651-737b4d69d68c/sam/sam_test.go (about)

     1  // Copyright ©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 sam
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"flag"
    11  	"fmt"
    12  	"io"
    13  	"reflect"
    14  	"sort"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  
    19  	"gopkg.in/check.v1"
    20  )
    21  
    22  var (
    23  	bam    = flag.Bool("bam", false, "output failing bam data for inspection")
    24  	allbam = flag.Bool("allbam", false, "output all bam data for inspection")
    25  )
    26  
    27  type failure bool
    28  
    29  func (f failure) String() string {
    30  	if f {
    31  		return "fail"
    32  	}
    33  	return "ok"
    34  }
    35  
    36  func Test(t *testing.T) { check.TestingT(t) }
    37  
    38  type S struct{}
    39  
    40  var _ = check.Suite(&S{})
    41  
    42  func (s *S) TestCloneHeader(c *check.C) {
    43  	for _, h := range []*Header{
    44  		headerHG00096_1000,
    45  	} {
    46  		c.Check(h, check.DeepEquals, h.Clone())
    47  	}
    48  }
    49  
    50  func (s *S) TestSpecExamples(c *check.C) {
    51  	sr, err := NewReader(bytes.NewReader(specExamples.data))
    52  	c.Assert(err, check.Equals, nil)
    53  	h := sr.Header()
    54  	c.Check(h.Version, check.Equals, specExamples.header.Version)
    55  	c.Check(h.SortOrder, check.Equals, specExamples.header.SortOrder)
    56  	c.Check(h.GroupOrder, check.Equals, specExamples.header.GroupOrder)
    57  	c.Check(h.Comments, check.DeepEquals, specExamples.header.Comments)
    58  
    59  	var buf bytes.Buffer
    60  	sw, err := NewWriter(&buf, h, FlagDecimal)
    61  	c.Assert(err, check.Equals, nil)
    62  	for i, expect := range specExamples.records {
    63  		r, err := sr.Read()
    64  		if err != nil {
    65  			c.Errorf("Unexpected early error: %v", err)
    66  			continue
    67  		}
    68  		c.Check(r.Name, check.Equals, expect.Name)
    69  		c.Check(r.Pos, check.Equals, expect.Pos) // Zero-based here.
    70  		c.Check(r.Flags, check.Equals, expect.Flags)
    71  		if r.Flags&Unmapped == 0 {
    72  			c.Check(r.Ref, check.Not(check.Equals), nil)
    73  			if r.Ref != nil {
    74  				c.Check(r.Ref.Name(), check.Equals, h.Refs()[0].Name())
    75  			}
    76  		} else {
    77  			c.Check(r.Ref, check.Equals, nil)
    78  		}
    79  		c.Check(r.MatePos, check.Equals, expect.MatePos) // Zero-based here.
    80  		c.Check(r.Cigar, check.DeepEquals, expect.Cigar)
    81  		c.Check(r.Cigar.IsValid(r.Seq.Length), check.Equals, true)
    82  		c.Check(r.TempLen, check.Equals, expect.TempLen)
    83  		c.Check(r.Seq, check.DeepEquals, expect.Seq, check.Commentf("got:%q expected:%q", r.Seq.Expand(), expect.Seq.Expand()))
    84  		c.Check(r.Qual, check.DeepEquals, expect.Qual) // No valid qualities here.
    85  		c.Check(r.End(), check.Equals, specExamples.readEnds[i], check.Commentf("unexpected end position for %q at %v, got:%d expected:%d", r.Name, r.Pos, r.End(), specExamples.readEnds[i]))
    86  		c.Check(r.AuxFields, check.DeepEquals, expect.AuxFields)
    87  
    88  		parsedCigar, err := ParseCigar([]byte(specExamples.cigars[i]))
    89  		c.Check(err, check.Equals, nil)
    90  		c.Check(parsedCigar, check.DeepEquals, expect.Cigar)
    91  
    92  		// In all the examples the last base of the read and the last
    93  		// base of the ref are valid, so we can check this.
    94  		expSeq := r.Seq.Expand()
    95  		c.Check(specExamples.ref[r.End()-1], check.Equals, expSeq[len(expSeq)-1])
    96  
    97  		// Test round trip.
    98  		err = sw.Write(r)
    99  		c.Check(err, check.Equals, nil)
   100  		b, err := r.MarshalText()
   101  		c.Check(err, check.Equals, nil)
   102  		var nr Record
   103  		c.Check(nr.UnmarshalSAM(sr.Header(), b), check.Equals, nil)
   104  		c.Check(&nr, check.DeepEquals, r)
   105  	}
   106  	c.Check(buf.String(), check.DeepEquals, string(specExamples.data))
   107  }
   108  
   109  func mustAux(a Aux, err error) Aux {
   110  	if err != nil {
   111  		panic(err)
   112  	}
   113  	return a
   114  }
   115  
   116  var specExamples = struct {
   117  	ref      string
   118  	data     []byte
   119  	header   Header
   120  	records  []*Record
   121  	cigars   []string
   122  	readEnds []int
   123  }{
   124  	ref: "AGCATGTTAGATAAGATAGCTGTGCTAGTAGGCAGTCAGCGCCAT",
   125  	data: []byte(`@HD	VN:1.5	SO:coordinate
   126  @SQ	SN:ref	LN:45
   127  @CO	--------------------------------------------------------
   128  @CO	Coor     12345678901234  5678901234567890123456789012345
   129  @CO	ref      AGCATGTTAGATAA**GATAGCTGTGCTAGTAGGCAGTCAGCGCCAT
   130  @CO	--------------------------------------------------------
   131  @CO	+r001/1        TTAGATAAAGGATA*CTG
   132  @CO	+r002         aaaAGATAA*GGATA
   133  @CO	+r003       gcctaAGCTAA
   134  @CO	+r004                     ATAGCT..............TCAGC
   135  @CO	-r003                            ttagctTAGGC
   136  @CO	-r001/2                                        CAGCGGCAT
   137  @CO	--------------------------------------------------------
   138  r001	99	ref	7	30	8M2I4M1D3M	=	37	39	TTAGATAAAGGATACTG	*
   139  r002	0	ref	9	30	3S6M1P1I4M	*	0	0	AAAAGATAAGGATA	*
   140  r003	0	ref	9	30	5S6M	*	0	0	GCCTAAGCTAA	*	SA:Z:ref,29,-,6H5M,17,0;
   141  r004	0	ref	16	30	6M14N5M	*	0	0	ATAGCTTCAGC	*
   142  r003	2064	ref	29	17	6H5M	*	0	0	TAGGC	*	SA:Z:ref,9,+,5S6M,30,1;
   143  r001	147	ref	37	30	9M	=	7	-39	CAGCGGCAT	*	NM:i:1
   144  `),
   145  	header: Header{
   146  		Version:    "1.5",
   147  		SortOrder:  Coordinate,
   148  		GroupOrder: GroupUnspecified,
   149  		Comments: []string{
   150  			"--------------------------------------------------------",
   151  			"Coor     12345678901234  5678901234567890123456789012345",
   152  			"ref      AGCATGTTAGATAA**GATAGCTGTGCTAGTAGGCAGTCAGCGCCAT",
   153  			"--------------------------------------------------------",
   154  			"+r001/1        TTAGATAAAGGATA*CTG",
   155  			"+r002         aaaAGATAA*GGATA",
   156  			"+r003       gcctaAGCTAA",
   157  			"+r004                     ATAGCT..............TCAGC",
   158  			"-r003                            ttagctTAGGC",
   159  			"-r001/2                                        CAGCGGCAT",
   160  			"--------------------------------------------------------",
   161  		},
   162  	},
   163  	records: []*Record{
   164  		{
   165  			Name: "r001",
   166  			Pos:  6,
   167  			MapQ: 30,
   168  			Cigar: Cigar{
   169  				NewCigarOp(CigarMatch, 8),
   170  				NewCigarOp(CigarInsertion, 2),
   171  				NewCigarOp(CigarMatch, 4),
   172  				NewCigarOp(CigarDeletion, 1),
   173  				NewCigarOp(CigarMatch, 3),
   174  			},
   175  			Flags:   Paired | ProperPair | MateReverse | Read1,
   176  			MatePos: 36,
   177  			TempLen: 39,
   178  			Seq:     NewSeq([]byte("TTAGATAAAGGATACTG")),
   179  			Qual:    []uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   180  		},
   181  		{
   182  			Name: "r002",
   183  			Pos:  8,
   184  			MapQ: 30,
   185  			Cigar: Cigar{
   186  				NewCigarOp(CigarSoftClipped, 3),
   187  				NewCigarOp(CigarMatch, 6),
   188  				NewCigarOp(CigarPadded, 1),
   189  				NewCigarOp(CigarInsertion, 1),
   190  				NewCigarOp(CigarMatch, 4),
   191  			},
   192  			MatePos: -1,
   193  			TempLen: 0,
   194  			Seq:     NewSeq([]byte("AAAAGATAAGGATA")),
   195  			Qual:    []uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   196  		},
   197  		{
   198  			Name: "r003",
   199  			Pos:  8,
   200  			MapQ: 30,
   201  			Cigar: Cigar{
   202  				NewCigarOp(CigarSoftClipped, 5),
   203  				NewCigarOp(CigarMatch, 6),
   204  			},
   205  			MatePos: -1,
   206  			TempLen: 0,
   207  			Seq:     NewSeq([]byte("GCCTAAGCTAA")),
   208  			Qual:    []uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   209  			AuxFields: []Aux{
   210  				mustAux(NewAux(NewTag("SA"), "ref,29,-,6H5M,17,0;")),
   211  			},
   212  		},
   213  		{
   214  			Name: "r004",
   215  			Pos:  15,
   216  			MapQ: 30,
   217  			Cigar: Cigar{
   218  				NewCigarOp(CigarMatch, 6),
   219  				NewCigarOp(CigarSkipped, 14),
   220  				NewCigarOp(CigarMatch, 5),
   221  			},
   222  			MatePos: -1,
   223  			TempLen: 0,
   224  			Seq:     NewSeq([]byte("ATAGCTTCAGC")),
   225  			Qual:    []uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   226  		},
   227  		{
   228  			Name: "r003",
   229  			Pos:  28,
   230  			MapQ: 17,
   231  			Cigar: Cigar{
   232  				NewCigarOp(CigarHardClipped, 6),
   233  				NewCigarOp(CigarMatch, 5),
   234  			},
   235  			Flags:   Reverse | Supplementary,
   236  			MatePos: -1,
   237  			TempLen: 0,
   238  			Seq:     NewSeq([]byte("TAGGC")),
   239  			Qual:    []uint8{0xff, 0xff, 0xff, 0xff, 0xff},
   240  			AuxFields: []Aux{
   241  				mustAux(NewAux(NewTag("SA"), "ref,9,+,5S6M,30,1;")),
   242  			},
   243  		},
   244  		{
   245  			Name: "r001",
   246  			Pos:  36,
   247  			MapQ: 30,
   248  			Cigar: Cigar{
   249  				NewCigarOp(CigarMatch, 9),
   250  			},
   251  			Flags:   Paired | ProperPair | Reverse | Read2,
   252  			MatePos: 6,
   253  			TempLen: -39,
   254  			Seq:     NewSeq([]byte("CAGCGGCAT")),
   255  			Qual:    []uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   256  			AuxFields: []Aux{
   257  				mustAux(NewAux(NewTag("NM"), uint(1))),
   258  			},
   259  		},
   260  	},
   261  	cigars: []string{
   262  		"8M2I4M1D3M",
   263  		"3S6M1P1I4M",
   264  		"5S6M",
   265  		"6M14N5M",
   266  		"6H5M",
   267  		"9M",
   268  	},
   269  	// These coordinates are all open (and zero-based) so that
   270  	// a slice of the reference doesn't need any alteration.
   271  	readEnds: []int{
   272  		22,
   273  		18,
   274  		14,
   275  		40,
   276  		33,
   277  		45,
   278  	},
   279  }
   280  
   281  var endTests = []struct {
   282  	cigar Cigar
   283  	end   int
   284  }{
   285  	{
   286  		cigar: Cigar{
   287  			NewCigarOp(CigarMatch, 20),
   288  			NewCigarOp(CigarBack, 5),
   289  			NewCigarOp(CigarMatch, 20),
   290  		},
   291  		end: 35,
   292  	},
   293  	{
   294  		cigar: Cigar{
   295  			NewCigarOp(CigarMatch, 10),
   296  			NewCigarOp(CigarBack, 3),
   297  			NewCigarOp(CigarMatch, 11),
   298  		},
   299  		end: 18,
   300  	},
   301  	{
   302  		cigar: Cigar{
   303  			NewCigarOp(CigarHardClipped, 10),
   304  			NewCigarOp(CigarBack, 3),
   305  		},
   306  		end: 0,
   307  	},
   308  	{
   309  		cigar: Cigar{
   310  			NewCigarOp(CigarMatch, 3),
   311  			NewCigarOp(CigarHardClipped, 10),
   312  		},
   313  		end: 3,
   314  	},
   315  	{
   316  		cigar: Cigar{
   317  			NewCigarOp(CigarMatch, 3),
   318  			NewCigarOp(CigarSkipped, 10),
   319  		},
   320  		end: 13,
   321  	},
   322  	{
   323  		cigar: Cigar{
   324  			NewCigarOp(CigarSkipped, 10),
   325  			NewCigarOp(CigarMatch, 3),
   326  		},
   327  		end: 13,
   328  	},
   329  	{
   330  		cigar: Cigar{
   331  			NewCigarOp(CigarMatch, 3),
   332  			NewCigarOp(CigarSoftClipped, 10),
   333  			NewCigarOp(CigarHardClipped, 10),
   334  		},
   335  		end: 3,
   336  	},
   337  	{
   338  		cigar: Cigar{
   339  			NewCigarOp(CigarBack, 10),
   340  			NewCigarOp(CigarSkipped, 10),
   341  			NewCigarOp(CigarBack, 10),
   342  			NewCigarOp(CigarSkipped, 10),
   343  			NewCigarOp(CigarMatch, 3),
   344  		},
   345  		end: 3,
   346  	},
   347  	{
   348  		cigar: Cigar{
   349  			NewCigarOp(CigarBack, 10),
   350  			NewCigarOp(CigarSkipped, 10),
   351  			NewCigarOp(CigarBack, 5),
   352  			NewCigarOp(CigarSkipped, 10),
   353  			NewCigarOp(CigarMatch, 3),
   354  		},
   355  		end: 8,
   356  	},
   357  }
   358  
   359  func (s *S) TestEnd(c *check.C) {
   360  	for _, test := range endTests {
   361  		c.Check((&Record{Cigar: test.cigar}).End(), check.Equals, test.end)
   362  	}
   363  }
   364  
   365  var cigarTests = []struct {
   366  	cigar  Cigar
   367  	length int
   368  	valid  bool
   369  }{
   370  	{
   371  		cigar:  nil,
   372  		length: 0,
   373  		valid:  true,
   374  	},
   375  
   376  	// One thought is that if B is really intended only to provide the ability
   377  	// to store CG and similar data where the read "skips" back a few bases now
   378  	// and again vs. the reference one thing that would make this much easier
   379  	// on those parsing SAM/BAM would be to limit the use of the B operator so
   380  	// that it cannot skip backwards past the beginning of the read.
   381  	//
   382  	// So something like 20M5B20M would be valid, but 50M5000B20M would not be.
   383  	//
   384  	// http://sourceforge.net/p/samtools/mailman/message/28466477/
   385  	{ // 20M5B20M
   386  		cigar: Cigar{
   387  			NewCigarOp(CigarMatch, 20),
   388  			NewCigarOp(CigarBack, 5),
   389  			NewCigarOp(CigarMatch, 20),
   390  		},
   391  		length: 40,
   392  		valid:  true,
   393  	},
   394  	{ // 50M5000B20M
   395  		cigar: Cigar{
   396  			NewCigarOp(CigarMatch, 50),
   397  			NewCigarOp(CigarBack, 5000),
   398  			NewCigarOp(CigarMatch, 20),
   399  		},
   400  		length: 70,
   401  		valid:  false,
   402  	},
   403  
   404  	// LH's example at http://sourceforge.net/p/samtools/mailman/message/28463294/
   405  	{ // 10M3B11M
   406  		// REF:: GCATACGATCGACTAGTCACGT
   407  		// READ: --ATACGATCGA----------
   408  		// READ: ---------CGACTAGTCAC--
   409  		cigar: Cigar{
   410  			NewCigarOp(CigarMatch, 10),
   411  			NewCigarOp(CigarBack, 3),
   412  			NewCigarOp(CigarMatch, 11),
   413  		},
   414  		length: 21,
   415  		valid:  true,
   416  	},
   417  
   418  	{
   419  		cigar: Cigar{
   420  			NewCigarOp(CigarHardClipped, 10),
   421  			NewCigarOp(CigarBack, 3),
   422  			NewCigarOp(CigarMatch, 11),
   423  		},
   424  		length: 11,
   425  		valid:  false,
   426  	},
   427  	{
   428  		cigar: Cigar{
   429  			NewCigarOp(CigarHardClipped, 10),
   430  			NewCigarOp(CigarBack, 3),
   431  		},
   432  		length: 0,
   433  		valid:  true,
   434  	},
   435  	{
   436  		cigar: Cigar{
   437  			NewCigarOp(CigarMatch, 3),
   438  			NewCigarOp(CigarHardClipped, 10),
   439  		},
   440  		length: 3,
   441  		valid:  true,
   442  	},
   443  	{
   444  		cigar: Cigar{
   445  			NewCigarOp(CigarMatch, 3),
   446  			NewCigarOp(CigarHardClipped, 10),
   447  			NewCigarOp(CigarHardClipped, 10),
   448  		},
   449  		length: 3,
   450  		valid:  false,
   451  	},
   452  	{
   453  		cigar: Cigar{
   454  			NewCigarOp(CigarMatch, 3),
   455  			NewCigarOp(CigarHardClipped, 10),
   456  			NewCigarOp(CigarSoftClipped, 10),
   457  		},
   458  		length: 13,
   459  		valid:  false,
   460  	},
   461  	{
   462  		cigar: Cigar{
   463  			NewCigarOp(CigarMatch, 3),
   464  			NewCigarOp(CigarSoftClipped, 10),
   465  			NewCigarOp(CigarHardClipped, 10),
   466  		},
   467  		length: 13,
   468  		valid:  true,
   469  	},
   470  
   471  	// Stupid, but not reason not to be valid. We only care if the
   472  	// there is a base from the query being used left of the start.
   473  	{
   474  		cigar: Cigar{
   475  			NewCigarOp(CigarBack, 10),
   476  			NewCigarOp(CigarSkipped, 10),
   477  			NewCigarOp(CigarBack, 10),
   478  			NewCigarOp(CigarSkipped, 10),
   479  			NewCigarOp(CigarMatch, 3),
   480  		},
   481  		length: 3,
   482  		valid:  true,
   483  	},
   484  }
   485  
   486  func (s *S) TestCigarIsValid(c *check.C) {
   487  	for _, test := range cigarTests {
   488  		c.Check(test.cigar.IsValid(test.length), check.Equals, test.valid)
   489  	}
   490  }
   491  
   492  func (s *S) TestNoHeader(c *check.C) {
   493  	sam := []byte(`r001	99	ref	7	30	8M2I4M1D3M	=	37	39	TTAGATAAAGGATACTG	*
   494  r002	0	ref	9	30	3S6M1P1I4M	*	0	0	AAAAGATAAGGATA	*
   495  r003	0	ref	9	30	5S6M	*	0	0	GCCTAAGCTAA	*	SA:Z:ref,29,-,6H5M,17,0;
   496  r004	0	ref	16	30	6M14N5M	*	0	0	ATAGCTTCAGC	*
   497  r003	2064	ref	29	17	6H5M	*	0	0	TAGGC	*	SA:Z:ref,9,+,5S6M,30,1;
   498  r001	147	ref	37	30	9M	=	7	-39	CAGCGGCAT	*	NM:i:1
   499  `)
   500  
   501  	sr, err := NewReader(bytes.NewReader(sam))
   502  	c.Assert(err, check.Equals, nil)
   503  	h := sr.Header()
   504  	c.Check(h.Version, check.Equals, "")
   505  	c.Check(h.SortOrder, check.Equals, UnknownOrder)
   506  	c.Check(h.GroupOrder, check.Equals, GroupUnspecified)
   507  	c.Check(h.Comments, check.DeepEquals, []string(nil))
   508  	for {
   509  		_, err := sr.Read()
   510  		if err != nil {
   511  			break
   512  		}
   513  	}
   514  	refs := sr.Header().Refs()
   515  	c.Assert(len(refs), check.Equals, 1)
   516  	c.Check(refs[0].String(), check.Equals, "@SQ\tSN:ref\tLN:0")
   517  }
   518  
   519  func (s *S) TestIterator(c *check.C) {
   520  	sam := [][]byte{
   521  		[]byte(`r001	99	ref	7	30	8M2I4M1D3M	=	37	39	TTAGATAAAGGATACTG	*
   522  r002	0	ref	9	30	3S6M1P1I4M	*	0	0	AAAAGATAAGGATA	*
   523  r003	0	ref	9	30	5S6M	*	0	0	GCCTAAGCTAA	*	SA:Z:ref,29,-,6H5M,17,0;
   524  r004	0	ref	16	30	6M14N5M	*	0	0	ATAGCTTCAGC	*
   525  r003	2064	ref	29	17	6H5M	*	0	0	TAGGC	*	SA:Z:ref,9,+,5S6M,30,1;
   526  r001	147	ref	37	30	9M	=	7	-39	CAGCGGCAT	*	NM:i:1
   527  r005	4	ref	37	0	*	=	0	0	CAGCGGCAT	*
   528  `),
   529  		[]byte(`@HD	VN:1.5	SO:coordinate
   530  @SQ	SN:ref	LN:45
   531  @CO	--------------------------------------------------------
   532  @CO	Coor     12345678901234  5678901234567890123456789012345
   533  @CO	ref      AGCATGTTAGATAA**GATAGCTGTGCTAGTAGGCAGTCAGCGCCAT
   534  @CO	--------------------------------------------------------
   535  @CO	+r001/1        TTAGATAAAGGATA*CTG
   536  @CO	+r002         aaaAGATAA*GGATA
   537  @CO	+r003       gcctaAGCTAA
   538  @CO	+r004                     ATAGCT..............TCAGC
   539  @CO	-r003                            ttagctTAGGC
   540  @CO	-r001/2                                        CAGCGGCAT
   541  @CO	-r005     <unmapped>
   542  @CO	--------------------------------------------------------
   543  r001	99	ref	7	30	8M2I4M1D3M	=	37	39	TTAGATAAAGGATACTG	*
   544  r002	0	ref	9	30	3S6M1P1I4M	*	0	0	AAAAGATAAGGATA	*
   545  r003	0	ref	9	30	5S6M	*	0	0	GCCTAAGCTAA	*	SA:Z:ref,29,-,6H5M,17,0;
   546  r004	0	ref	16	30	6M14N5M	*	0	0	ATAGCTTCAGC	*
   547  r003	2064	ref	29	17	6H5M	*	0	0	TAGGC	*	SA:Z:ref,9,+,5S6M,30,1;
   548  r001	147	ref	37	30	9M	=	7	-39	CAGCGGCAT	*	NM:i:1
   549  r005	4	ref	37	0	*	=	0	0	CAGCGGCAT	*
   550  `),
   551  	}
   552  
   553  	for _, s := range sam {
   554  		sr, err := NewReader(bytes.NewReader(s))
   555  		c.Assert(err, check.Equals, nil)
   556  		i := NewIterator(sr)
   557  		var n int
   558  		for i.Next() {
   559  			n++
   560  		}
   561  		c.Check(i.Error(), check.Equals, nil)
   562  		c.Check(n, check.Equals, 7)
   563  	}
   564  }
   565  
   566  var auxTests = []struct {
   567  	sam string
   568  
   569  	want []*Record
   570  }{
   571  	{
   572  		sam: `1f001i8gk#GGCG#AA	0	*	0	0	*	*	0	0	*	*	NH:i:2	HI:i:1	AS:i:13	nM:i:4	NM:i:4	MD:Z:2C0T2T1C13	jM:B:c,-1	jI:B:i,-1
   573  1f001i8gk#GGCG#AA	0	*	0	0	*	*	0	0	*	*	NH:i:2	HI:i:2	AS:i:12	nM:i:0	NM:i:0	MD:Z:22	jM:B:c,0	jI:B:i,629,1095	fT:f:3.14
   574  1f001i8gk#GGCG#AA	0	*	0	0	*	*	0	0	*	*	NE:i:-100	MN:i:-1000
   575  `,
   576  		want: []*Record{
   577  			{
   578  				Name:    "1f001i8gk#GGCG#AA",
   579  				Pos:     -1,
   580  				MatePos: -1,
   581  				AuxFields: AuxFields{
   582  					{
   583  						0x4e, 0x48, 0x43, 0x02, // |NHC.|
   584  					},
   585  					{
   586  						0x48, 0x49, 0x43, 0x01, // |HIC.|
   587  					},
   588  					{
   589  						0x41, 0x53, 0x43, 0x0d, // |ASC.|
   590  					},
   591  					{
   592  						0x6e, 0x4d, 0x43, 0x04, // |nMC.|
   593  					},
   594  					{
   595  						0x4e, 0x4d, 0x43, 0x04, // |NMC.|
   596  					},
   597  					{
   598  						0x4d, 0x44, 0x5a, 0x32, 0x43, 0x30, 0x54, 0x32, 0x54, 0x31, 0x43, 0x31, 0x33, // |MDZ2C0T2T1C13|
   599  					},
   600  					{
   601  						0x6a, 0x4d, 0x42, 0x63, 0x01, 0x00, 0x00, 0x00, 0xff, // |jMBc.....|
   602  					},
   603  					{
   604  						0x6a, 0x49, 0x42, 0x69, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, // |jIBi........|
   605  					},
   606  				},
   607  			},
   608  			{
   609  				Name:    "1f001i8gk#GGCG#AA",
   610  				Pos:     -1,
   611  				MatePos: -1,
   612  				AuxFields: AuxFields{
   613  					{
   614  						0x4e, 0x48, 0x43, 0x02, // |NHC.|
   615  					},
   616  					{
   617  						0x48, 0x49, 0x43, 0x02, // |HIC.|
   618  					},
   619  					{
   620  						0x41, 0x53, 0x43, 0x0c, // |ASC.|
   621  					},
   622  					{
   623  						0x6e, 0x4d, 0x43, 0x00, // |nMC.|
   624  					},
   625  					{
   626  						0x4e, 0x4d, 0x43, 0x00, // |NMC.|
   627  					},
   628  					{
   629  						0x4d, 0x44, 0x5a, 0x32, 0x32, // |MDZ22|
   630  					},
   631  					{
   632  						0x6a, 0x4d, 0x42, 0x63, 0x01, 0x00, 0x00, 0x00, 0x00, // |jMBc.....|
   633  					},
   634  					{
   635  						0x6a, 0x49, 0x42, 0x69, 0x02, 0x00, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x47, 0x04, 0x00, 0x00, // |jIBi....u...G...|
   636  					},
   637  					{
   638  						0x66, 0x54, 0x66, 0xc3, 0xf5, 0x48, 0x40, // |fTf..H@|
   639  					},
   640  				},
   641  			},
   642  			{
   643  				Name:    "1f001i8gk#GGCG#AA",
   644  				Pos:     -1,
   645  				MatePos: -1,
   646  				AuxFields: AuxFields{
   647  					{
   648  						0x4e, 0x45, 0x63, 0x9c, // |NEc.|
   649  					},
   650  					{
   651  						0x4d, 0x4e, 0x73, 0x18, 0xfc, // |MNs..|
   652  					},
   653  				},
   654  			},
   655  		},
   656  	},
   657  }
   658  
   659  func (s *S) TestAux(c *check.C) {
   660  	for _, test := range auxTests {
   661  		sr, err := NewReader(strings.NewReader(test.sam))
   662  		c.Assert(err, check.Equals, nil)
   663  		var recs []*Record
   664  		for {
   665  			r, err := sr.Read()
   666  			if err != nil {
   667  				c.Assert(err, check.Equals, io.EOF)
   668  				break
   669  			}
   670  			recs = append(recs, r)
   671  		}
   672  		c.Check(recs, check.DeepEquals, test.want)
   673  	}
   674  }
   675  
   676  func (s *S) TestIssue26(c *check.C) {
   677  	fuTag := NewTag("fu")
   678  
   679  	var issue26 = struct {
   680  		data   []byte
   681  		header Header
   682  		ref    Reference
   683  		rg     ReadGroup
   684  		prog   Program
   685  	}{
   686  		// This is a Pacific Biosciences header line. The SO is invalid.
   687  		data: []byte(`@HD	VN:1.5	SO:UNKNOWN	pb:3.0b7
   688  @SQ	SN:ref	LN:45	fu:bar
   689  @RG	ID:group	fu:bar
   690  @PG	ID:program	fu:bar
   691  `),
   692  		header: Header{
   693  			Version:    "1.5",
   694  			SortOrder:  UnknownOrder,
   695  			GroupOrder: GroupUnspecified,
   696  		},
   697  		ref: Reference{
   698  			id:        -1,
   699  			name:      "ref",
   700  			lRef:      45,
   701  			otherTags: []tagPair{{tag: fuTag, value: "bar"}},
   702  		},
   703  		rg: ReadGroup{
   704  			id:        -1,
   705  			name:      "group",
   706  			otherTags: []tagPair{{tag: fuTag, value: "bar"}},
   707  		},
   708  		prog: Program{
   709  			id:        -1,
   710  			uid:       "program",
   711  			otherTags: []tagPair{{tag: fuTag, value: "bar"}},
   712  		},
   713  	}
   714  
   715  	sr, err := NewReader(bytes.NewReader(issue26.data))
   716  	c.Assert(err, check.Equals, nil)
   717  	h := sr.Header()
   718  
   719  	c.Check(h.Version, check.Equals, issue26.header.Version)
   720  	c.Check(h.SortOrder, check.Equals, issue26.header.SortOrder)
   721  	c.Check(h.GroupOrder, check.Equals, issue26.header.GroupOrder)
   722  	c.Assert(len(h.Refs()), check.Equals, 1)
   723  	ref := h.Refs()[0].Clone()
   724  	c.Check(equalRefs(ref, &issue26.ref), check.Equals, true)
   725  	c.Check(ref.Get(refNameTag), check.Equals, "ref")
   726  	c.Check(ref.Get(refLengthTag), check.Equals, "45")
   727  	c.Check(ref.Get(fuTag), check.Equals, "bar")
   728  	c.Assert(len(h.RGs()), check.Equals, 1)
   729  	rg := h.RGs()[0].Clone()
   730  	c.Check(*rg, check.DeepEquals, issue26.rg)
   731  	c.Check(rg.Get(idTag), check.Equals, "group")
   732  	c.Check(rg.Get(fuTag), check.Equals, "bar")
   733  	c.Assert(len(h.Progs()), check.Equals, 1)
   734  	prog := h.Progs()[0].Clone()
   735  	c.Check(*prog, check.DeepEquals, issue26.prog)
   736  	c.Check(prog.Get(idTag), check.Equals, "program")
   737  	c.Check(prog.Get(fuTag), check.Equals, "bar")
   738  }
   739  
   740  func (s *S) TestParseISO8601(c *check.C) {
   741  	for _, test := range []struct {
   742  		value string
   743  		want  time.Time
   744  	}{
   745  		{value: "2017-05-10", want: time.Date(2017, 05, 10, 0, 0, 0, 0, time.Local)},
   746  		{value: "2017-05-10T21:02:29", want: time.Date(2017, 05, 10, 21, 02, 29, 0, time.Local)},
   747  		{value: "2017-05-10T21:02:29Z", want: time.Date(2017, 05, 10, 21, 02, 29, 0, time.UTC)},
   748  		{value: "2017-05-10T21:02:29+0900", want: time.Date(2017, 05, 10, 21, 02, 29, 0, time.FixedZone("0900", 9*3600))},
   749  		{value: "2010-10-19T00:00:00.000+00:00", want: time.Date(2010, 10, 19, 0, 0, 0, 0, time.FixedZone("0000", 0))},
   750  	} {
   751  		date, err := parseISO8601(test.value)
   752  		c.Check(err, check.Equals, nil)
   753  		c.Check(date.Equal(test.want), check.Equals, true)
   754  	}
   755  }
   756  
   757  var cigTests = []struct {
   758  	cig  []byte
   759  	ref  int
   760  	read int
   761  }{
   762  	{[]byte("151M"), 151, 151},
   763  	{[]byte("10S10M"), 10, 20},
   764  	{[]byte("11H11M"), 11, 11},
   765  	{[]byte("11H1D11M"), 12, 11},
   766  	{[]byte("5M21N5M"), 31, 10},
   767  	{[]byte("21N"), 21, 0},
   768  	{[]byte("0M1I1D"), 1, 1},
   769  	{[]byte("1000000000M"), 1e9, 1e9},
   770  	{[]byte("1000000000000M"), 1e12, 1e12},
   771  }
   772  
   773  func (s *S) TestLengths(c *check.C) {
   774  	for _, ct := range cigTests {
   775  		cig, err := ParseCigar(ct.cig)
   776  		c.Check(err, check.IsNil)
   777  		ref, read := cig.Lengths()
   778  		c.Check(ref, check.Equals, ct.ref)
   779  		c.Check(read, check.Equals, ct.read)
   780  	}
   781  }
   782  
   783  func (s *S) TestIssue32(c *check.C) {
   784  	sam := []byte(`@HD	VN:1.5	SO:coordinate
   785  @SQ	SN:name	LN:1
   786  @RG	ID:name
   787  @PG	ID:name
   788  `)
   789  
   790  	r, err := NewReader(bytes.NewReader(sam))
   791  	c.Check(err, check.Equals, nil)
   792  	h := r.Header()
   793  	c.Assert(len(h.Refs()), check.Equals, 1)
   794  	c.Check(h.Refs()[0].Name(), check.Equals, "name")
   795  	c.Assert(len(h.RGs()), check.Equals, 1)
   796  	c.Check(h.RGs()[0].Name(), check.Equals, "name")
   797  	c.Assert(len(h.Progs()), check.Equals, 1)
   798  	c.Check(h.Progs()[0].UID(), check.Equals, "name")
   799  }
   800  
   801  func (s *S) TestEqualRefs(c *check.C) {
   802  	a, err := NewReference("aaa", "assem", "species", 1234, nil, nil)
   803  	c.Assert(err, check.IsNil)
   804  	b := a.Clone()
   805  	c.Assert(b.Set(Tag{'T', 'A'}, "xxx"), check.IsNil)
   806  
   807  	c.Assert(equalRefs(a, b), check.Equals, false)
   808  	c.Assert(equalRefs(b, a), check.Equals, false)
   809  }
   810  
   811  func (s *S) TestAddClonedRef(c *check.C) {
   812  	sr, err := NewReader(bytes.NewReader(specExamples.data))
   813  	c.Assert(err, check.Equals, nil)
   814  	h := sr.Header()
   815  	ref := h.Refs()[0].Clone()
   816  	c.Check(h.AddReference(ref), check.Equals, nil)
   817  }
   818  
   819  func (s *S) TestRenames(c *check.C) {
   820  	sam := []byte(`@HD	VN:1.5	SO:coordinate
   821  @SQ	SN:name	LN:1
   822  @SQ	SN:taken	LN:1
   823  @RG	ID:name
   824  @RG	ID:taken
   825  @PG	ID:name
   826  @PG	ID:taken
   827  `)
   828  
   829  	r, err := NewReader(bytes.NewReader(sam))
   830  	c.Check(err, check.Equals, nil)
   831  	h := r.Header()
   832  	c.Assert(len(h.Refs()), check.Equals, 2)
   833  	c.Assert(h.Refs()[0].SetName("reference"), check.Equals, nil)
   834  	c.Check(h.Refs()[0].Name(), check.Equals, "reference")
   835  	c.Check(h.Refs()[0].SetName("taken"), check.DeepEquals, errors.New("sam: name exists"))
   836  
   837  	c.Assert(len(h.RGs()), check.Equals, 2)
   838  	c.Assert(h.RGs()[0].SetName("read group"), check.Equals, nil)
   839  	c.Check(h.RGs()[0].Name(), check.Equals, "read group")
   840  	c.Check(h.RGs()[0].SetName("taken"), check.DeepEquals, errors.New("sam: name exists"))
   841  
   842  	c.Assert(len(h.Progs()), check.Equals, 2)
   843  	c.Assert(h.Progs()[0].SetUID("program"), check.Equals, nil)
   844  	c.Check(h.Progs()[0].UID(), check.Equals, "program")
   845  	c.Check(h.Progs()[0].SetUID("taken"), check.DeepEquals, errors.New("sam: uid exists"))
   846  
   847  	ref, err := NewReference("ref", "", "", 1, nil, nil)
   848  	c.Assert(err, check.Equals, nil)
   849  	c.Assert(ref.SetName("new ref"), check.Equals, nil)
   850  
   851  	rg, err := NewReadGroup("rg", "", "", "", "", "", "", "", "", "", time.Time{}, 0)
   852  	c.Assert(err, check.Equals, nil)
   853  	c.Assert(rg.SetName("new rg"), check.Equals, nil)
   854  
   855  	prog := NewProgram("prog", "", "", "", "")
   856  	c.Assert(prog.SetUID("new prog"), check.Equals, nil)
   857  }
   858  
   859  func (s *S) TestSort(c *check.C) {
   860  	sr, err := NewReader(bytes.NewReader(specExamples.data))
   861  	c.Assert(err, check.Equals, nil)
   862  	i := NewIterator(sr)
   863  	var recs []*Record
   864  	for i.Next() {
   865  		recs = append(recs, i.Record())
   866  	}
   867  	c.Assert(i.Error(), check.Equals, nil)
   868  	recs = append(recs, &Record{Name: "000", Ref: nil, Pos: -1})
   869  
   870  	wantPos := []int{6, 8, 8, 15, 28, 36, -1}
   871  	sort.Sort(byCoordinate(recs))
   872  	for i, r := range recs {
   873  		c.Check(r.Pos, check.Equals, wantPos[i])
   874  	}
   875  
   876  	wantName := []string{"000", "r001", "r001", "r002", "r003", "r003", "r004"}
   877  	sort.Sort(byName(recs))
   878  	for i, r := range recs {
   879  		c.Check(r.Name, check.Equals, wantName[i])
   880  	}
   881  }
   882  
   883  type byName []*Record
   884  
   885  func (r byName) Len() int           { return len(r) }
   886  func (r byName) Less(i, j int) bool { return r[i].LessByName(r[j]) }
   887  func (r byName) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
   888  
   889  type byCoordinate []*Record
   890  
   891  func (r byCoordinate) Len() int           { return len(r) }
   892  func (r byCoordinate) Less(i, j int) bool { return r[i].LessByCoordinate(r[j]) }
   893  func (r byCoordinate) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
   894  
   895  func (s *S) TestRemoveReference(c *check.C) {
   896  	h := headerHG00096_1000.Clone()
   897  	h.RemoveReference(h.Refs()[2])
   898  	c.Check(len(h.Refs()), check.Equals, len(headerHG00096_1000.Refs())-1)
   899  	c.Check(fmt.Sprint(h.Refs()[1]), check.Equals, fmt.Sprint(headerHG00096_1000.Refs()[1]))
   900  	c.Check(fmt.Sprint(h.Refs()[2]), check.Equals, fmt.Sprint(headerHG00096_1000.Refs()[3]))
   901  	r := headerHG00096_1000.Refs()[2].Clone()
   902  	c.Check(h.AddReference(r), check.Equals, nil)
   903  	c.Check(len(h.Refs()), check.Equals, len(headerHG00096_1000.Refs()))
   904  }
   905  
   906  func (s *S) TestRemoveReadGroup(c *check.C) {
   907  	h := headerHG00096_1000.Clone()
   908  	h.RemoveReadGroup(h.RGs()[1])
   909  	c.Check(len(h.RGs()), check.Equals, len(headerHG00096_1000.RGs())-1)
   910  	c.Check(fmt.Sprint(h.RGs()[0]), check.Equals, fmt.Sprint(headerHG00096_1000.RGs()[0]))
   911  	c.Check(fmt.Sprint(h.RGs()[1]), check.Equals, fmt.Sprint(headerHG00096_1000.RGs()[2]))
   912  	r := headerHG00096_1000.RGs()[1].Clone()
   913  	c.Check(h.AddReadGroup(r), check.Equals, nil)
   914  	c.Check(len(h.RGs()), check.Equals, len(headerHG00096_1000.RGs()))
   915  }
   916  
   917  func (s *S) TestRemoveProgram(c *check.C) {
   918  	h := headerHG00096_1000.Clone()
   919  	h.RemoveProgram(h.Progs()[2])
   920  	c.Check(len(h.Progs()), check.Equals, len(headerHG00096_1000.Progs())-1)
   921  	c.Check(fmt.Sprint(h.Progs()[1]), check.Equals, fmt.Sprint(headerHG00096_1000.Progs()[1]))
   922  	c.Check(fmt.Sprint(h.Progs()[2]), check.Equals, fmt.Sprint(headerHG00096_1000.Progs()[3]))
   923  	p := headerHG00096_1000.Progs()[2].Clone()
   924  	c.Check(h.AddProgram(p), check.Equals, nil)
   925  	c.Check(len(h.Progs()), check.Equals, len(headerHG00096_1000.Progs()))
   926  }
   927  
   928  func (s *S) TestMergeHeaders(c *check.C) {
   929  	tests := []struct {
   930  		src   []*Header
   931  		want  *Header
   932  		links [][]*Reference
   933  		err   error
   934  	}{
   935  		{},
   936  		{
   937  			src:   []*Header{{}},
   938  			links: nil,
   939  			want:  &Header{},
   940  			err:   nil,
   941  		},
   942  		{
   943  			src: []*Header{
   944  				{refs: []*Reference{{id: 0, name: "ref", lRef: 45}}, seenRefs: set{"ref": 0}, seenGroups: set{}, seenProgs: set{}},
   945  				{refs: []*Reference{{id: 0, name: "ref", lRef: 45}}, seenRefs: set{"ref": 0}, seenGroups: set{}, seenProgs: set{}},
   946  			},
   947  			links: [][]*Reference{
   948  				{{id: 0, name: "ref", lRef: 45}},
   949  				{{id: 0, name: "ref", lRef: 45}},
   950  			},
   951  			want: &Header{
   952  				refs:       []*Reference{{id: 0, name: "ref", lRef: 45}},
   953  				seenRefs:   set{"ref": 0},
   954  				seenGroups: set{},
   955  				seenProgs:  set{},
   956  			},
   957  			err: nil,
   958  		},
   959  		{
   960  			src: []*Header{
   961  				{refs: []*Reference{{id: 0, name: "refa", lRef: 45}}, seenRefs: set{"refa": 0}, seenGroups: set{}, seenProgs: set{}},
   962  				{refs: []*Reference{{id: 0, name: "refb", lRef: 45}}, seenRefs: set{"refb": 0}, seenGroups: set{}, seenProgs: set{}},
   963  			},
   964  			links: [][]*Reference{
   965  				{{id: 0, name: "refa", lRef: 45}},
   966  				{{id: 1, name: "refb", lRef: 45}},
   967  			},
   968  			want: &Header{
   969  				refs: []*Reference{
   970  					{id: 0, name: "refa", lRef: 45},
   971  					{id: 1, name: "refb", lRef: 45},
   972  				},
   973  				seenRefs:   set{"refa": 0, "refb": 1},
   974  				seenGroups: set{},
   975  				seenProgs:  set{},
   976  			},
   977  			err: nil,
   978  		},
   979  		{
   980  			src: []*Header{
   981  				{refs: []*Reference{{id: 0, name: "ref", lRef: 45}}, seenRefs: set{"ref": 0}, seenGroups: set{}, seenProgs: set{}},
   982  				{refs: []*Reference{{id: 0, name: "ref", lRef: 44}}, seenRefs: set{"ref": 0}, seenGroups: set{}, seenProgs: set{}},
   983  			},
   984  			links: nil,
   985  			want:  nil,
   986  			err:   errors.New("sam: duplicate reference name"),
   987  		},
   988  	}
   989  	for _, test := range tests[3:] {
   990  		// Prepare the internal links that cannot be expressed statically.
   991  		if len(test.src) != 0 {
   992  			for _, r := range test.src[0].refs {
   993  				r.owner = test.src[0]
   994  			}
   995  		}
   996  		for _, in := range test.links {
   997  			for _, ref := range in {
   998  				ref.owner = test.want
   999  			}
  1000  		}
  1001  		if test.want != nil {
  1002  			for _, r := range test.want.refs {
  1003  				r.owner = test.want
  1004  			}
  1005  		}
  1006  
  1007  		// Set up for identical input case.
  1008  		var identical bool
  1009  		if len(test.src) == 2 {
  1010  			identical = reflect.DeepEqual(test.src[0], test.src[1])
  1011  		}
  1012  
  1013  		got, links, err := MergeHeaders(test.src)
  1014  		c.Check(err, check.DeepEquals, test.err)
  1015  		if err != nil {
  1016  			continue
  1017  		}
  1018  		c.Check(got, check.DeepEquals, test.want)
  1019  		c.Check(links, check.DeepEquals, test.links)
  1020  		if identical {
  1021  			c.Check(links[0][0], check.Equals, links[1][0])
  1022  		}
  1023  	}
  1024  }
  1025  
  1026  func newAux(tag Tag, value interface{}) Aux {
  1027  	aux, err := NewAux(tag, value)
  1028  	if err != nil {
  1029  		panic(err)
  1030  	}
  1031  	return aux
  1032  }
  1033  
  1034  func (s *S) TestBagID(c *check.C) {
  1035  	for _, test := range []struct {
  1036  		r         *Record
  1037  		id        int64
  1038  		expectErr bool
  1039  	}{
  1040  		{
  1041  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagIDTag, 33)}},
  1042  			33,
  1043  			false,
  1044  		},
  1045  		{
  1046  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagIDTag, "34")}},
  1047  			34,
  1048  			false,
  1049  		},
  1050  		{
  1051  			&Record{Name: "foo", Ref: nil, Pos: 123},
  1052  			-1,
  1053  			false,
  1054  		},
  1055  		{
  1056  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagIDTag, -4)}},
  1057  			-1,
  1058  			true,
  1059  		},
  1060  		{
  1061  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagIDTag, "abc")}},
  1062  			-1,
  1063  			true,
  1064  		},
  1065  		{
  1066  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagIDTag, 33), newAux(bagIDTag, 34)}},
  1067  			-1,
  1068  			true,
  1069  		},
  1070  	} {
  1071  
  1072  		id, err := test.r.BagID()
  1073  		c.Check(id, check.Equals, test.id)
  1074  		if test.expectErr {
  1075  			c.Check(err, check.Not(check.Equals), nil)
  1076  		} else {
  1077  			c.Check(err, check.Equals, nil)
  1078  		}
  1079  	}
  1080  }
  1081  
  1082  func (s *S) TestBagSize(c *check.C) {
  1083  	for _, test := range []struct {
  1084  		r         *Record
  1085  		id        int
  1086  		expectErr bool
  1087  	}{
  1088  		{
  1089  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagSizeTag, 33)}},
  1090  			33,
  1091  			false,
  1092  		},
  1093  		{
  1094  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagSizeTag, "34")}},
  1095  			-1,
  1096  			true,
  1097  		},
  1098  		{
  1099  			&Record{Name: "foo", Ref: nil, Pos: 123},
  1100  			-1,
  1101  			false,
  1102  		},
  1103  		{
  1104  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagSizeTag, -12)}},
  1105  			-1,
  1106  			true,
  1107  		},
  1108  		{
  1109  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagSizeTag, "abc")}},
  1110  			-1,
  1111  			true,
  1112  		},
  1113  		{
  1114  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(bagSizeTag, 33), newAux(bagSizeTag, 34)}},
  1115  			-1,
  1116  			true,
  1117  		},
  1118  	} {
  1119  
  1120  		id, err := test.r.BagSize()
  1121  		c.Check(id, check.Equals, test.id)
  1122  		if test.expectErr {
  1123  			c.Check(err, check.Not(check.Equals), nil)
  1124  		} else {
  1125  			c.Check(err, check.Equals, nil)
  1126  		}
  1127  	}
  1128  }
  1129  
  1130  func (s *S) TestDupType(c *check.C) {
  1131  	for _, test := range []struct {
  1132  		r         *Record
  1133  		dup       DupType
  1134  		expectErr bool
  1135  	}{
  1136  		{
  1137  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(dupTypeTag, "SQ")}},
  1138  			DupTypeSQ,
  1139  			false,
  1140  		},
  1141  		{
  1142  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(dupTypeTag, "LB")}},
  1143  			DupTypeLB,
  1144  			false,
  1145  		},
  1146  		{
  1147  			&Record{Name: "foo", Ref: nil, Pos: 123},
  1148  			DupTypeNone,
  1149  			false,
  1150  		},
  1151  		{
  1152  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(dupTypeTag, "abc")}},
  1153  			DupTypeNone,
  1154  			true,
  1155  		},
  1156  		{
  1157  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(dupTypeTag, "SQ"), newAux(dupTypeTag, "SQ")}},
  1158  			DupTypeNone,
  1159  			true,
  1160  		},
  1161  	} {
  1162  
  1163  		dup, err := test.r.DupType()
  1164  		c.Check(dup, check.Equals, test.dup)
  1165  		if test.expectErr {
  1166  			c.Check(err, check.Not(check.Equals), nil)
  1167  		} else {
  1168  			c.Check(err, check.Equals, nil)
  1169  		}
  1170  	}
  1171  }
  1172  
  1173  func (s *S) TestLibraryBagSize(c *check.C) {
  1174  	for _, test := range []struct {
  1175  		r         *Record
  1176  		expected  int
  1177  		expectErr bool
  1178  	}{
  1179  		{
  1180  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(libraryBagSizeTag, 3)}},
  1181  			3,
  1182  			false,
  1183  		},
  1184  		{
  1185  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(libraryBagSizeTag, 1)}},
  1186  			1,
  1187  			false,
  1188  		},
  1189  		{
  1190  			&Record{Name: "foo", Ref: nil, Pos: 123},
  1191  			-1,
  1192  			false,
  1193  		},
  1194  		{
  1195  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(libraryBagSizeTag, "abc")}},
  1196  			-1,
  1197  			true,
  1198  		},
  1199  		{
  1200  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(libraryBagSizeTag, -4)}},
  1201  			-1,
  1202  			true,
  1203  		},
  1204  	} {
  1205  
  1206  		libraryBagSize, err := test.r.LibraryBagSize()
  1207  		c.Check(libraryBagSize, check.Equals, test.expected)
  1208  		if test.expectErr {
  1209  			c.Check(err, check.Not(check.Equals), nil)
  1210  		} else {
  1211  			c.Check(err, check.Equals, nil)
  1212  		}
  1213  	}
  1214  }
  1215  
  1216  func (s *S) TestLinearDup(c *check.C) {
  1217  	for _, test := range []struct {
  1218  		r         *Record
  1219  		linearDup LinearDupState
  1220  		expectErr bool
  1221  	}{
  1222  		{
  1223  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearDupTag, "primary")}},
  1224  			LinearPrimary,
  1225  			false,
  1226  		},
  1227  		{
  1228  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearDupTag, "duplicate")}},
  1229  			LinearDuplicate,
  1230  			false,
  1231  		},
  1232  		{
  1233  			&Record{Name: "foo", Ref: nil, Pos: 123},
  1234  			LinearNone,
  1235  			false,
  1236  		},
  1237  		{
  1238  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearDupTag, "abc")}},
  1239  			LinearNone,
  1240  			true,
  1241  		},
  1242  		{
  1243  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{
  1244  				newAux(linearDupTag, "primary"),
  1245  				newAux(linearDupTag, "duplicate"),
  1246  			}},
  1247  			LinearNone,
  1248  			true,
  1249  		},
  1250  	} {
  1251  
  1252  		linearDup, err := test.r.LinearDup()
  1253  		c.Check(linearDup, check.Equals, test.linearDup)
  1254  		if test.expectErr {
  1255  			c.Check(err, check.Not(check.Equals), nil)
  1256  		} else {
  1257  			c.Check(err, check.Equals, nil)
  1258  		}
  1259  	}
  1260  }
  1261  
  1262  func (s *S) TestLinearBagID(c *check.C) {
  1263  	for _, test := range []struct {
  1264  		r         *Record
  1265  		id        int64
  1266  		expectErr bool
  1267  	}{
  1268  		{
  1269  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagIDTag, 33)}},
  1270  			33,
  1271  			false,
  1272  		},
  1273  		{
  1274  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagIDTag, "34")}},
  1275  			34,
  1276  			false,
  1277  		},
  1278  		{
  1279  			&Record{Name: "foo", Ref: nil, Pos: 123},
  1280  			-1,
  1281  			false,
  1282  		},
  1283  		{
  1284  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagIDTag, -4)}},
  1285  			-1,
  1286  			true,
  1287  		},
  1288  		{
  1289  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagIDTag, "abc")}},
  1290  			-1,
  1291  			true,
  1292  		},
  1293  		{
  1294  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagIDTag, 33), newAux(linearBagIDTag, 34)}},
  1295  			-1,
  1296  			true,
  1297  		},
  1298  	} {
  1299  
  1300  		id, err := test.r.LinearBagID()
  1301  		c.Check(id, check.Equals, test.id)
  1302  		if test.expectErr {
  1303  			c.Check(err, check.Not(check.Equals), nil)
  1304  		} else {
  1305  			c.Check(err, check.Equals, nil)
  1306  		}
  1307  	}
  1308  }
  1309  
  1310  func (s *S) TestLinearBagSize(c *check.C) {
  1311  	for _, test := range []struct {
  1312  		r         *Record
  1313  		id        int
  1314  		expectErr bool
  1315  	}{
  1316  		{
  1317  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagSizeTag, 33)}},
  1318  			33,
  1319  			false,
  1320  		},
  1321  		{
  1322  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagSizeTag, "34")}},
  1323  			-1,
  1324  			true,
  1325  		},
  1326  		{
  1327  			&Record{Name: "foo", Ref: nil, Pos: 123},
  1328  			-1,
  1329  			false,
  1330  		},
  1331  		{
  1332  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagSizeTag, -12)}},
  1333  			-1,
  1334  			true,
  1335  		},
  1336  		{
  1337  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagSizeTag, "abc")}},
  1338  			-1,
  1339  			true,
  1340  		},
  1341  		{
  1342  			&Record{Name: "foo", Ref: nil, Pos: 123, AuxFields: AuxFields{newAux(linearBagSizeTag, 33), newAux(linearBagSizeTag, 34)}},
  1343  			-1,
  1344  			true,
  1345  		},
  1346  	} {
  1347  
  1348  		id, err := test.r.LinearBagSize()
  1349  		c.Check(id, check.Equals, test.id)
  1350  		if test.expectErr {
  1351  			c.Check(err, check.Not(check.Equals), nil)
  1352  		} else {
  1353  			c.Check(err, check.Equals, nil)
  1354  		}
  1355  	}
  1356  }
  1357  
  1358  func BenchmarkParseCigar(b *testing.B) {
  1359  	cig := []byte("69S17M5I30M1D45M1D23M5I14M2I4M1I10M2D7M1D6M14I33M1D6M1I7M1I18M1I8M1D4M1D4M2D57M1D21M1D6M1I14M1I7M1I3M1I9M1D3M1D7M1D37M1D9M1I5M1I15M4I12M1D10M1I10M1D8M1D26M7I12M1D20M1I36M1I22M3D8M1I23M1I13M2D10M1D12M1I15M6D4M1D4M1D1M2D5M1D3M17D1M1D13M3D7M1I29M2I9M1D2M4D7M2D8M5D3M1D1M1D23M1D10M6D19M3I24M1D8M1I11M6D14M1I5M8I12M1D8M2D5M2D2M1D23M1D11M4I35M2I19M1I4M1D13M7I33M1D21M3D2M1D9M4I19M1I14M1D7M1I41M1D23M3I18M1I6M1I13M1D9M1D1M1D20M1D23M5D8M1I13M2I11M1D78M2I18M10D9M2D10M1D10M2I6M1D3M1D21M2I7M1D7M2I12M1D20M2D18M1I12M1D8M4D18M1D6M1D20M1D14M1I1M2I23M1I10M1D7M1I15M1D4M1I9M1D11M1D12M1I8M1D21M1I13M2I59M1D12M1D18M1D13M1D22M1D13M1I19M1D13M1D19M1I11M2I27M2D10M1D17M6D13M2D17M1D13M1D19M1I3M1D13M2I33M1I26M2D9M2I21M2D10M1D36M1D32M5I23M1D13M2D17M1I14M2I24M1I5M2I8M2I24M2I9M1D7M1D2M1D15M3I19M1I2M1D3M1I7M1D5M2D24M5I1M4I33M1I13M3I34M1I2M1I23M1D3M2I8M1I5M5S")
  1360  	for i := 0; i < b.N; i++ {
  1361  		_, err := ParseCigar(cig)
  1362  		if err != nil {
  1363  			panic(err)
  1364  		}
  1365  	}
  1366  }
  1367  
  1368  func benchmarkAux(b *testing.B, aux []byte) {
  1369  	for i := 0; i < b.N; i++ {
  1370  		_, err := ParseAux(aux)
  1371  		if err != nil {
  1372  			b.Fatal(err)
  1373  		}
  1374  	}
  1375  }
  1376  
  1377  func BenchmarkParseAuxInt(b *testing.B)   { benchmarkAux(b, []byte("NM:i:1")) }
  1378  func BenchmarkParseAuxZ(b *testing.B)     { benchmarkAux(b, []byte("SA:Z:ref,29,-,6H5M,17,0;")) }
  1379  func BenchmarkParseAuxFloat(b *testing.B) { benchmarkAux(b, []byte("FL:f:100042.42")) }
  1380  func BenchmarkParseAuxArray(b *testing.B) { benchmarkAux(b, []byte("BB:B:i,629,1095")) }