From b9c9937c3dd6138b12ed119d066641a922ef597f Mon Sep 17 00:00:00 2001 From: Keoni Gandall Date: Tue, 12 Dec 2023 14:53:07 -0800 Subject: [PATCH] Purged gff --- lib/bio/gff/example_test.go | 170 ------------------ lib/bio/gff/gff.go | 332 ------------------------------------ lib/bio/gff/gff_test.go | 146 ---------------- 3 files changed, 648 deletions(-) delete mode 100644 lib/bio/gff/example_test.go delete mode 100644 lib/bio/gff/gff.go delete mode 100644 lib/bio/gff/gff_test.go diff --git a/lib/bio/gff/example_test.go b/lib/bio/gff/example_test.go deleted file mode 100644 index 7be3d8e..0000000 --- a/lib/bio/gff/example_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package gff_test - -import ( - "bytes" - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/koeng101/dnadesign/lib/bio/gff" - "github.com/koeng101/dnadesign/lib/transform" -) - -// This example shows how to open a gff file and search for a gene given its -// locus tag. We then display the EC number of that particular gene. -func Example_basic() { - sequence, _ := gff.Read("../../data/ecoli-mg1655-short.gff") - for _, feature := range sequence.Features { - if feature.Attributes["locus_tag"] == "b0003" { - fmt.Println(feature.Attributes["EC_number"]) - } - } - // Output: 2.7.1.39 -} - -func ExampleRead() { - sequence, _ := gff.Read("../../data/ecoli-mg1655-short.gff") - fmt.Println(sequence.Meta.Name) - // Output: U00096.3 -} - -func ExampleParse() { - file, _ := os.Open("../../data/ecoli-mg1655-short.gff") - sequence, _ := gff.Parse(file) - - fmt.Println(sequence.Meta.Name) - // Output: U00096.3 -} - -func ExampleBuild() { - sequence, _ := gff.Read("../../data/ecoli-mg1655-short.gff") - gffBytes, _ := gff.Build(sequence) - gffReader := bytes.NewReader(gffBytes) - reparsedSequence, _ := gff.Parse(gffReader) - - fmt.Println(reparsedSequence.Meta.Name) - // Output: U00096.3 -} - -func ExampleWrite() { - tmpDataDir, err := os.MkdirTemp("", "data-*") - if err != nil { - fmt.Println(err.Error()) - } - defer os.RemoveAll(tmpDataDir) - - sequence, _ := gff.Read("../../data/ecoli-mg1655-short.gff") - - tmpGffFilePath := filepath.Join(tmpDataDir, "ecoli-mg1655-short.gff") - _ = gff.Write(sequence, tmpGffFilePath) - - testSequence, _ := gff.Read(tmpGffFilePath) - - fmt.Println(testSequence.Meta.Name) - // Output: U00096.3 -} - -func ExampleGff_AddFeature() { - // Sequence for greenflourescent protein (GFP) that we're using as test data for this example. - gfpSequence := "ATGGCTAGCAAAGGAGAAGAACTTTTCACTGGAGTTGTCCCAATTCTTGTTGAATTAGATGGTGATGTTAATGGGCACAAATTTTCTGTCAGTGGAGAGGGTGAAGGTGATGCTACATACGGAAAGCTTACCCTTAAATTTATTTGCACTACTGGAAAACTACCTGTTCCATGGCCAACACTTGTCACTACTTTCTCTTATGGTGTTCAATGCTTTTCCCGTTATCCGGATCATATGAAACGGCATGACTTTTTCAAGAGTGCCATGCCCGAAGGTTATGTACAGGAACGCACTATATCTTTCAAAGATGACGGGAACTACAAGACGCGTGCTGAAGTCAAGTTTGAAGGTGATACCCTTGTTAATCGTATCGAGTTAAAAGGTATTGATTTTAAAGAAGATGGAAACATTCTCGGACACAAACTCGAGTACAACTATAACTCACACAATGTATACATCACGGCAGACAAACAAAAGAATGGAATCAAAGCTAACTTCAAAATTCGCCACAACATTGAAGATGGATCCGTTCAACTAGCAGACCATTATCAACAAAATACTCCAATTGGCGATGGCCCTGTCCTTTTACCAGACAACCATTACCTGTCGACACAATCTGCCCTTTCGAAAGATCCCAACGAAAAGCGTGACCACATGGTCCTTCTTGAGTTTGTAACTGCTGCTGGGATTACACATGGCATGGATGAGCTCTACAAATAA" - - // initialize sequence and feature structs. - var sequence gff.Gff - var feature gff.Feature - - // set the initialized sequence struct's sequence. - sequence.Sequence = gfpSequence - - // Set the initialized feature name and sequence location. - feature.Location = gff.Location{} - feature.Location.Start = 0 - feature.Location.End = len(sequence.Sequence) - - // Add the GFP feature to the sequence struct. - _ = sequence.AddFeature(&feature) - - // get the GFP feature sequence string from the sequence struct. - featureSequence, _ := feature.GetSequence() - - // check to see if the feature was inserted properly into the sequence. - fmt.Println(gfpSequence == featureSequence) - - // Output: true -} - -func ExampleFeature_GetSequence() { - // Sequence for greenflourescent protein (GFP) that we're using as test data for this example. - gfpSequence := "ATGGCTAGCAAAGGAGAAGAACTTTTCACTGGAGTTGTCCCAATTCTTGTTGAATTAGATGGTGATGTTAATGGGCACAAATTTTCTGTCAGTGGAGAGGGTGAAGGTGATGCTACATACGGAAAGCTTACCCTTAAATTTATTTGCACTACTGGAAAACTACCTGTTCCATGGCCAACACTTGTCACTACTTTCTCTTATGGTGTTCAATGCTTTTCCCGTTATCCGGATCATATGAAACGGCATGACTTTTTCAAGAGTGCCATGCCCGAAGGTTATGTACAGGAACGCACTATATCTTTCAAAGATGACGGGAACTACAAGACGCGTGCTGAAGTCAAGTTTGAAGGTGATACCCTTGTTAATCGTATCGAGTTAAAAGGTATTGATTTTAAAGAAGATGGAAACATTCTCGGACACAAACTCGAGTACAACTATAACTCACACAATGTATACATCACGGCAGACAAACAAAAGAATGGAATCAAAGCTAACTTCAAAATTCGCCACAACATTGAAGATGGATCCGTTCAACTAGCAGACCATTATCAACAAAATACTCCAATTGGCGATGGCCCTGTCCTTTTACCAGACAACCATTACCTGTCGACACAATCTGCCCTTTCGAAAGATCCCAACGAAAAGCGTGACCACATGGTCCTTCTTGAGTTTGTAACTGCTGCTGGGATTACACATGGCATGGATGAGCTCTACAAATAA" - - // initialize sequence and feature structs. - var sequence gff.Gff - var feature gff.Feature - - // set the initialized sequence struct's sequence. - sequence.Sequence = gfpSequence - - // Set the initialized feature name and sequence location. - feature.Location.Start = 0 - feature.Location.End = len(sequence.Sequence) - - // Add the GFP feature to the sequence struct. - _ = sequence.AddFeature(&feature) - - // get the GFP feature sequence string from the sequence struct. - featureSequence, _ := feature.GetSequence() - - // check to see if the feature was inserted properly into the sequence. - fmt.Println(gfpSequence == featureSequence) - - // Output: true -} - -func TestFeature_GetSequence(t *testing.T) { - // This test is a little too complex and contrived for an example function. - // Essentially, it's testing GetSequence()'s ability to parse and retrieve sequences from complex location structures. - // This was originally covered in the old package system it was not covered in the new package system so I decided to include it here. - - // Sequence for greenflourescent protein (GFP) that we're using as test data for this example. - gfpSequence := "ATGGCTAGCAAAGGAGAAGAACTTTTCACTGGAGTTGTCCCAATTCTTGTTGAATTAGATGGTGATGTTAATGGGCACAAATTTTCTGTCAGTGGAGAGGGTGAAGGTGATGCTACATACGGAAAGCTTACCCTTAAATTTATTTGCACTACTGGAAAACTACCTGTTCCATGGCCAACACTTGTCACTACTTTCTCTTATGGTGTTCAATGCTTTTCCCGTTATCCGGATCATATGAAACGGCATGACTTTTTCAAGAGTGCCATGCCCGAAGGTTATGTACAGGAACGCACTATATCTTTCAAAGATGACGGGAACTACAAGACGCGTGCTGAAGTCAAGTTTGAAGGTGATACCCTTGTTAATCGTATCGAGTTAAAAGGTATTGATTTTAAAGAAGATGGAAACATTCTCGGACACAAACTCGAGTACAACTATAACTCACACAATGTATACATCACGGCAGACAAACAAAAGAATGGAATCAAAGCTAACTTCAAAATTCGCCACAACATTGAAGATGGATCCGTTCAACTAGCAGACCATTATCAACAAAATACTCCAATTGGCGATGGCCCTGTCCTTTTACCAGACAACCATTACCTGTCGACACAATCTGCCCTTTCGAAAGATCCCAACGAAAAGCGTGACCACATGGTCCTTCTTGAGTTTGTAACTGCTGCTGGGATTACACATGGCATGGATGAGCTCTACAAATAA" - - sequenceLength := len(gfpSequence) - - // Splitting the sequence into two parts to make a multi-location feature. - sequenceFirstHalf := gfpSequence[:sequenceLength/2] - sequenceSecondHalf := transform.ReverseComplement(gfpSequence[sequenceLength/2:]) // This feature is reverse complemented. - - // rejoining the two halves into a single string where the second half of the sequence is reverse complemented. - gfpSequenceModified := sequenceFirstHalf + sequenceSecondHalf - - // initialize sequence and feature structs. - var sequence gff.Gff - var feature gff.Feature - - // set the initialized sequence struct's sequence. - sequence.Sequence = gfpSequenceModified - // initialize sublocations to be usedin the feature. - - var subLocation gff.Location - var subLocationReverseComplemented gff.Location - - subLocation.Start = 0 - subLocation.End = sequenceLength / 2 - - subLocationReverseComplemented.Start = sequenceLength / 2 - subLocationReverseComplemented.End = sequenceLength - subLocationReverseComplemented.Complement = true // According to genbank complement means reverse complement. What a country. - - feature.Location.SubLocations = []gff.Location{subLocation, subLocationReverseComplemented} - - // Add the GFP feature to the sequence struct. - _ = sequence.AddFeature(&feature) - - // get the GFP feature sequence string from the sequence struct. - featureSequence, _ := feature.GetSequence() - - // check to see if the feature was inserted properly into the sequence. - if gfpSequence != featureSequence { - t.Error("Feature sequence was not properly retrieved.") - } -} diff --git a/lib/bio/gff/gff.go b/lib/bio/gff/gff.go deleted file mode 100644 index 0abd002..0000000 --- a/lib/bio/gff/gff.go +++ /dev/null @@ -1,332 +0,0 @@ -/* -Package gff provides gff parsers and writers. - -GFF stands for "general feature format". It is an alternative to GenBank for -storing data about genomic sequences. While not often used in synthetic biology -research, it is more commonly used in bioinformatics for digesting features of -genomic sequences. - -This package provides a parser and writer to convert between the gff file -format and the more general poly.Sequence struct. -*/ -package gff - -import ( - "bytes" - "errors" - "io" - "os" - "sort" - "strconv" - "strings" - - "lukechampine.com/blake3" - - "github.com/koeng101/dnadesign/lib/transform" -) - -var ( - readAllFn = io.ReadAll - atoiFn = strconv.Atoi - openFn = os.Open -) - -// Gff is a struct that represents a gff file. -type Gff struct { - Meta Meta - Features []Feature // will need a GetFeatures interface to standardize - Sequence string -} - -// Meta holds meta information about a gff file. -type Meta struct { - Name string `json:"name"` - Description string `json:"description"` - Version string `json:"gff_version"` - RegionStart int `json:"region_start"` - RegionEnd int `json:"region_end"` - Size int `json:"size"` - SequenceHash string `json:"sequence_hash"` - SequenceHashFunction string `json:"hash_function"` - CheckSum [32]byte `json:"checkSum"` // blake3 checksum of the parsed file itself. Useful for if you want to check if incoming genbank/gff files are different. -} - -// Feature is a struct that represents a feature in a gff file. -type Feature struct { - Name string `json:"name"` - Source string `json:"source"` - Type string `json:"type"` - Score string `json:"score"` - Strand string `json:"strand"` - Phase string `json:"phase"` - Attributes map[string]string `json:"attributes"` - Location Location `json:"location"` - ParentSequence *Gff `json:"-"` -} - -// Location is a struct that represents a location in a gff file. -type Location struct { - Start int `json:"start"` - End int `json:"end"` - Complement bool `json:"complement"` - Join bool `json:"join"` - FivePrimePartial bool `json:"five_prime_partial"` - ThreePrimePartial bool `json:"three_prime_partial"` - SubLocations []Location `json:"sub_locations"` -} - -// AddFeature takes a feature and adds it to the Gff struct. -func (sequence *Gff) AddFeature(feature *Feature) error { - feature.ParentSequence = sequence - featureCopy := *feature - sequence.Features = append(sequence.Features, featureCopy) - return nil -} - -// GetSequence takes a feature and returns a sequence string for that feature. -func (feature Feature) GetSequence() (string, error) { - return getFeatureSequence(feature, feature.Location) -} - -// getFeatureSequence takes a feature and location object and returns a sequence string. -func getFeatureSequence(feature Feature, location Location) (string, error) { - var sequenceBuffer bytes.Buffer - var sequenceString string - parentSequence := feature.ParentSequence.Sequence - - if len(location.SubLocations) == 0 { - sequenceBuffer.WriteString(parentSequence[location.Start:location.End]) - } else { - for _, subLocation := range location.SubLocations { - sequence, _ := getFeatureSequence(feature, subLocation) - sequenceBuffer.WriteString(sequence) - } - } - - // reverse complements resulting string if needed. - if location.Complement { - sequenceString = transform.ReverseComplement(sequenceBuffer.String()) - } else { - sequenceString = sequenceBuffer.String() - } - - return sequenceString, nil -} - -// Parse Takes in a string representing a gffv3 file and parses it into an Sequence object. -func Parse(file io.Reader) (Gff, error) { - fileBytes, err := readAllFn(file) - if err != nil { - return Gff{}, err - } - - gffString := string(fileBytes) - gff := Gff{} - - // Add the CheckSum to sequence (blake3) - gff.Meta.CheckSum = blake3.Sum256(fileBytes) - - lines := strings.Split(gffString, "\n") - regionStringArray, endOfMetaInfo, err := extractInfoFromField(lines, "##sequence-region") - metaString := lines[0:endOfMetaInfo] - versionString := metaString[0] - if err != nil { - return Gff{}, err - } - // get name for general meta - meta := Meta{} - meta.Name = regionStringArray[1] // Formally region name, but changed to name here for generality/interoperability. - - // get meta info only specific to GFF files - meta.Version = strings.Split(versionString, " ")[1] - meta.RegionStart, err = atoiFn(regionStringArray[2]) - if err != nil { - return Gff{}, err - } - meta.RegionEnd, err = atoiFn(regionStringArray[3]) - if err != nil { - return Gff{}, err - } - meta.Size = meta.RegionEnd - meta.RegionStart - - var sequenceBuffer bytes.Buffer - fastaFlag := false - for _, line := range lines { - if line == "##FASTA" { - fastaFlag = true - } else if len(line) == 0 { - continue - } else if line[0:2] == "##" || line[0:2] == "#!" { - continue - } else if fastaFlag && line[0:1] != ">" { - // sequence.Sequence = sequence.Sequence + line - sequenceBuffer.WriteString(line) - } else if fastaFlag && line[0:1] == ">" { - gff.Meta.Description = line - } else { - record := Feature{} - fields := strings.Split(line, "\t") - record.Name = fields[0] - record.Source = fields[1] - record.Type = fields[2] - - // Indexing starts at 1 for gff so we need to shift down for Sequence 0 index. - record.Location.Start, err = atoiFn(fields[3]) - if err != nil { - return Gff{}, err - } - - record.Location.Start-- - record.Location.End, err = atoiFn(fields[4]) - if err != nil { - return Gff{}, err - } - - record.Score = fields[5] - record.Strand = fields[6] - record.Phase = fields[7] - record.Attributes = make(map[string]string) - attributes := fields[8] - // var eqIndex int - attributeSlice := strings.Split(attributes, ";") - - for _, attribute := range attributeSlice { - attributeSplit := strings.Split(attribute, "=") - key := attributeSplit[0] - value := attributeSplit[1] - record.Attributes[key] = value - } - err = gff.AddFeature(&record) - if err != nil { - return Gff{}, err - } - } - } - gff.Sequence = sequenceBuffer.String() - gff.Meta = meta - - return gff, err -} - -// regionString takes in the lines array,fieldName that is needed in gff file, and -// returns the region containing fieldName if found -// throws error if not found -func extractInfoFromField(lines []string, fieldName string) ([]string, int, error) { - index := 0 - endOfMetaInfo := 0 - for lineIndex, line := range lines { - if strings.Contains(line, "#") { - if strings.Contains(line, fieldName) { - index = lineIndex - } - continue - } - endOfMetaInfo = lineIndex - break - } - if index == 0 && fieldName != "gff-version" { - return nil, 0, errors.New("the given file does not have any meta information") - } - return strings.Split(lines[index], " "), endOfMetaInfo, nil -} - -// Build takes an Annotated sequence and returns a byte array representing a gff to be written out. -func Build(sequence Gff) ([]byte, error) { - var gffBuffer bytes.Buffer - - versionString := "##gff-version 3 \n" - if sequence.Meta.Version != "" { - versionString = "##gff-version " + sequence.Meta.Version + "\n" - } - - gffBuffer.WriteString(versionString) - - name := "Sequence" - start := "1" - end := strconv.Itoa(sequence.Meta.RegionEnd) - - if sequence.Meta.Name != "" { - name = sequence.Meta.Name - } - - if sequence.Meta.RegionStart != 0 { - start = strconv.Itoa(sequence.Meta.RegionStart) - } - - regionString := "##sequence-region " + name + " " + start + " " + end + "\n" - gffBuffer.WriteString(regionString) - - for _, feature := range sequence.Features { - var featureString string - - featureSource := "feature" - if feature.Source != "" { - featureSource = feature.Source - } - - featureType := "unknown" - if feature.Type != "" { - featureType = feature.Type - } - - // Indexing starts at 1 for gff so we need to shift up from Sequence 0 index. - featureStart := strconv.Itoa(feature.Location.Start + 1) - featureEnd := strconv.Itoa(feature.Location.End) - - featureScore := feature.Score - featureStrand := feature.Strand - featurePhase := feature.Phase - var featureAttributes string - - keys := make([]string, 0, len(feature.Attributes)) - for key := range feature.Attributes { - keys = append(keys, key) - } - sort.Strings(keys) - - for _, key := range keys { - attributeString := key + "=" + feature.Attributes[key] + ";" - featureAttributes += attributeString - } - - if len(featureAttributes) > 0 { - featureAttributes = featureAttributes[0 : len(featureAttributes)-1] - } - TAB := "\t" - featureString = feature.Name + TAB + featureSource + TAB + featureType + TAB + featureStart + TAB + featureEnd + TAB + featureScore + TAB + featureStrand + TAB + featurePhase + TAB + featureAttributes + "\n" - gffBuffer.WriteString(featureString) - } - - gffBuffer.WriteString("###\n") - gffBuffer.WriteString("##FASTA\n") - gffBuffer.WriteString(">" + sequence.Meta.Name + "\n") - - for letterIndex, letter := range sequence.Sequence { - letterIndex++ - if letterIndex%70 == 0 && letterIndex != 0 && letterIndex != sequence.Meta.RegionEnd { - gffBuffer.WriteRune(letter) - gffBuffer.WriteString("\n") - } else { - gffBuffer.WriteRune(letter) - } - } - gffBuffer.WriteString("\n") - return gffBuffer.Bytes(), nil -} - -// Read takes in a filepath for a .gffv3 file and parses it into an Annotated poly.Sequence struct. -func Read(path string) (Gff, error) { - file, err := openFn(path) - if err != nil { - return Gff{}, err - } - - sequence, err := Parse(file) - return sequence, err -} - -// Write takes an poly.Sequence struct and a path string and writes out a gff to that path. -func Write(sequence Gff, path string) error { - gff, _ := Build(sequence) - return os.WriteFile(path, gff, 0644) -} diff --git a/lib/bio/gff/gff_test.go b/lib/bio/gff/gff_test.go deleted file mode 100644 index 7a6e029..0000000 --- a/lib/bio/gff/gff_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package gff - -import ( - "bytes" - "errors" - "io" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/pmezard/go-difflib/difflib" -) - -/****************************************************************************** - -Gff related tests and benchmarks begin here. - -******************************************************************************/ - -// TODO should delete output files. - -func TestGffIO(t *testing.T) { - tmpDataDir, err := os.MkdirTemp("", "data-*") - if err != nil { - t.Error(err) - } - defer os.RemoveAll(tmpDataDir) - - testInputPath := "../../data/ecoli-mg1655-short.gff" - tmpGffFilePath := filepath.Join(tmpDataDir, "ecoli-mg1655-short.gff") - - testSequence, _ := Read(testInputPath) - _ = Write(testSequence, tmpGffFilePath) - - readTestSequence, _ := Read(tmpGffFilePath) - - if diff := cmp.Diff(testSequence, readTestSequence, cmpopts.IgnoreFields(Feature{}, "ParentSequence")); diff != "" { - t.Errorf("Parsing the output of Build() does not produce the same output as parsing the original file read with ReadGff(). Got this diff:\n%s", diff) - } - - original, _ := os.ReadFile(testInputPath) - builtOutput, _ := os.ReadFile(tmpGffFilePath) - gffDiff := difflib.UnifiedDiff{ - A: difflib.SplitLines(string(original)), - B: difflib.SplitLines(string(builtOutput)), - FromFile: testInputPath, - ToFile: tmpGffFilePath, - Context: 3, - } - - gffDiffText, _ := difflib.GetUnifiedDiffString(gffDiff) - - if gffDiffText != "" { - t.Errorf("Build() does not output the same file as was input through ReadGff(). Got this diff:\n%s", gffDiffText) - } -} - -// testing that readAllFn() returns an error. -func TestParseReader_error(t *testing.T) { - parseErr := errors.New("parse error") - oldReadAllFn := readAllFn - readAllFn = func(r io.Reader) ([]byte, error) { - return nil, parseErr - } - defer func() { - readAllFn = oldReadAllFn - }() - _, err := Parse(strings.NewReader("")) - if err != parseErr { - t.Errorf("Parse() did not return the expected error. Got %v, expected %v", err, parseErr) - } -} - -// testing that all Atoi() calls return an error. -func TestParseAtoi_error(t *testing.T) { - file, _ := openFn("../../data/ecoli-mg1655-short.gff") - fileBytes, _ := readAllFn(file) - fileString := string(fileBytes) - recievedAtoiInputs := []string{} - - parseErr := errors.New("parse error") - oldAtoiFn := atoiFn - // helper function to see if the input string for atoiFn is in the recievedAtoiInputs slice. - contains := func(stringSlice []string, expression string) bool { - for _, input := range stringSlice { - if input == expression { - return true - } - } - return false - } - atoiFn = func(gffString string) (int, error) { - if !contains(recievedAtoiInputs, gffString) { - recievedAtoiInputs = append(recievedAtoiInputs, gffString) - // length = len(recievedAtoiInputs) - return 0, parseErr - } - return oldAtoiFn(gffString) - } - - defer func() { - atoiFn = oldAtoiFn - }() - for index := 0; index <= 10; index++ { - var gffBuffer bytes.Buffer - gffBuffer.WriteString(fileString) - _, _ = Parse(&gffBuffer) - } -} - -// testing that Read can return an appropriate error. -func TestRead_error(t *testing.T) { - readErr := errors.New("open : no such file or directory") - oldOpenFn := openFn - openFn = func(filepath string) (*os.File, error) { - return nil, readErr - } - defer func() { - openFn = oldOpenFn - }() - _, err := Read("../../data/ecoli-mg1655-short.gff") - if err != readErr { - t.Errorf("Read() did not return the expected error. Got %v, expected %v", err, readErr) - } -} - -func BenchmarkReadGff(b *testing.B) { - for i := 0; i < b.N; i++ { - _, _ = Read("../../data/ecoli-mg1655-short.gff") - } -} - -func BenchmarkReadGff1(b *testing.B) { BenchmarkReadGff(b) } -func BenchmarkReadGff10(b *testing.B) { BenchmarkReadGff(b) } -func BenchmarkReadGff100(b *testing.B) { BenchmarkReadGff(b) } -func BenchmarkReadGff1000(b *testing.B) { BenchmarkReadGff(b) } -func BenchmarkReadGff10000(b *testing.B) { BenchmarkReadGff(b) } - -/****************************************************************************** - -Gff related tests and benchmarks end here. - -******************************************************************************/