Skip to content

Commit

Permalink
fix unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobinso committed Oct 22, 2023
1 parent b8cda23 commit c7444ee
Show file tree
Hide file tree
Showing 14 changed files with 178 additions and 201 deletions.
2 changes: 1 addition & 1 deletion js/bam/bamReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class BamReader {

for (let c of chunks) {
const ba = await this._blockLoader.getData(c.minv, c.maxv)
const done = BamUtils.decodeBamRecords(ba, c.minv.offset, alignmentContainer, this.indexToChr, chrId, bpStart, bpEnd, this.filter)
const done = BamUtils.decodeBamRecords(ba, c.minv.offset, alignmentContainer, this.header.chrNames, chrId, bpStart, bpEnd, this.filter)
if (done) {
break
}
Expand Down
85 changes: 55 additions & 30 deletions js/bam/bamReaderNonIndexed.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import {buildOptions, isDataURL} from "../util/igvUtils.js"
*/
class BamReaderNonIndexed {

chrAliasTable = new Map()

constructor(config, genome) {
this.config = config
this.genome = genome
Expand All @@ -45,52 +47,75 @@ class BamReaderNonIndexed {
BamUtils.setReaderDefaults(this, config)
}

// Return an alignment container
/**
*
* @param chr
* @param bpStart
* @param bpEnd
* @returns {Promise<AlignmentContainer>}
*/
async readAlignments(chr, bpStart, bpEnd) {

if (this.alignmentCache) {
const header = this.header
const queryChr = header.chrAliasTable.hasOwnProperty(chr) ? header.chrAliasTable[chr] : chr
const qAlignments = this.alignmentCache.queryFeatures(queryChr, bpStart, bpEnd)
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config)
for (let a of qAlignments) {
alignmentContainer.push(a)
}
alignmentContainer.finish()
return alignmentContainer

} else {
if (!this.alignmentCache) {
// For a non-indexed BAM file all alignments are read at once and cached.
let unc
if (this.isDataUri) {
const data = decodeDataURI(this.bamPath)
const unc = BGZip.unbgzf(data.buffer)
this.parseAlignments(unc)
return this.fetchAlignments(chr, bpStart, bpEnd)
unc = BGZip.unbgzf(data.buffer)
} else {
const arrayBuffer = await igvxhr.loadArrayBuffer(this.bamPath, buildOptions(this.config))
const unc = BGZip.unbgzf(arrayBuffer)
this.parseAlignments(unc)
return this.fetchAlignments(chr, bpStart, bpEnd)
unc = BGZip.unbgzf(arrayBuffer)
}
this.alignmentCache = this.#parseAlignments(unc)
}

const queryChr = await this.#getQueryChr(chr)
const qAlignments = this.alignmentCache.queryFeatures(queryChr, bpStart, bpEnd)
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config)
for (let a of qAlignments) {
alignmentContainer.push(a)
}
alignmentContainer.finish()
return alignmentContainer
}

parseAlignments(data) {
#parseAlignments(data) {
const alignments = []
this.header = BamUtils.decodeBamHeader(data)
BamUtils. decodeBamRecords(data, this.header.size, alignments, this.header.chrNames)
this.alignmentCache = new FeatureCache(alignments, this.genome)
BamUtils.decodeBamRecords(data, this.header.size, alignments, this.header.chrNames)
return new FeatureCache(alignments, this.genome)
}

fetchAlignments(chr, bpStart, bpEnd) {
const queryChr = this.header.chrAliasTable.hasOwnProperty(chr) ? this.header.chrAliasTable[chr] : chr
const features = this.alignmentCache.queryFeatures(queryChr, bpStart, bpEnd)
const alignmentContainer = new AlignmentContainer(chr, bpStart, bpEnd, this.config)
for (let feature of features) {
alignmentContainer.push(feature)
async #getQueryChr(chr) {

const ownNames = new Set(this.header.chrNames)
if (ownNames.has(chr)) {
return chr
}
alignmentContainer.finish()
return alignmentContainer

if (this.chrAliasTable.has(chr)) {
return this.chrAliasTable.get(chr)
}

// Try alias

if (this.genome) {
const aliasRecord = await this.genome.getAliasRecord(chr)
let alias
if (aliasRecord) {
const aliases = Object.keys(aliasRecord)
.filter(k => k !== "start" && k !== "end")
.map(k => aliasRecord[k])
.filter(a => ownNames.has(a))
if (aliases.length > 0) {
alias = aliases[0]
}
}
this.chrAliasTable.set(chr, alias) // alias may be undefined => no alias exists. Setting prevents repeated attempts
return alias
}

return chr
}

}
Expand Down
8 changes: 4 additions & 4 deletions js/bigwig/bwReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,10 @@ class BWReader {

// Use a trix index if we have one to map entered term to indexed value in bb file
if (this._trix) {
term = term.toLowerCase()
const trixResults = await this._trix.search(term)
if (trixResults && trixResults.has(term)) { // <= exact matches only for now
term = trixResults.get(term)[0]
const termLower = term.toLowerCase()
const trixResults = await this._trix.search(termLower)
if (trixResults && trixResults.has(termLower)) { // <= exact matches only for now
term = trixResults.get(termLower)[0]
}
}

Expand Down
4 changes: 2 additions & 2 deletions js/genome/genome.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Genome {
this.cytobandSource = new CytobandFile(config.cytobandURL, Object.assign({}, config))
}

if (false !== config.wholeGenomeView) {
if (false !== config.wholeGenomeView && this.chromosomes.size > 0) {
// Set chromosome order for WG view and chromosome pulldown. If chromosome order is not specified sort
if (config.chromosomeOrder) {
if (Array.isArray(config.chromosomeOrder)) {
Expand All @@ -73,7 +73,7 @@ class Genome {
this.wgChromosomeNames = config.chromosomeOrder.split(',').map(nm => nm.trim())
}
} else {
this.wgChromosomeNames = trimSmallChromosomes(chromosomes)
this.wgChromosomeNames = trimSmallChromosomes(this.chromosomes)
}
}

Expand Down
8 changes: 4 additions & 4 deletions test/testHtsgetReader.js → test/old/testHtsgetReader.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import "./utils/mockObjects.js"
import "../utils/mockObjects.js"
import {assert} from 'chai'
import HtsgetBamReader from "../js/htsget/htsgetBamReader.js"
import HtsgetVariantReader from "../js/htsget/htsgetVariantReader.js"
import Browser from "../js/browser.js"
import HtsgetBamReader from "../../js/htsget/htsgetBamReader.js"
import HtsgetVariantReader from "../../js/htsget/htsgetVariantReader.js"
import Browser from "../../js/browser.js"


// Mock genome with "1,2,3..." name convention
Expand Down
63 changes: 35 additions & 28 deletions test/testAlignmentUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,53 @@ suite("testAlignmentUtils", function () {

test("Alignment packing", async function () {
this.timeout(10000)
const chr = 'chr22'
const start = 24375132
const end = 24385311

const bamReader = new BamReaderNonIndexed({
type: 'bam',
url: 'test/data/bam/gstt1_sample.bam',
indexed: false
})
await _testPacking('chr22')
await _testPacking('22') // Test aliasing

const alignmentContainer = await bamReader.readAlignments(chr, start, end)

const rows = packAlignmentRows(alignmentContainer.alignments, start, end, false)
async function _testPacking(chr) {
const start = 24375132
const end = 24385311

let count = 0
for (let r of rows) count += r.alignments.length
const bamReader = new BamReaderNonIndexed({
type: 'bam',
url: 'test/data/bam/gstt1_sample.bam',
indexed: false
})

// All alignments are packed
assert.equal(alignmentContainer.alignments.length, count)
const alignmentContainer = await bamReader.readAlignments(chr, start, end)

// No duplicates
const seen = new Set()
for (let r of rows) {
for (let a of r.alignments) {
if (seen.has(a)) {
assert.fail(a, undefined, 'Alignment seen twice')
const rows = packAlignmentRows(alignmentContainer.alignments, start, end, false)

let count = 0
for (let r of rows) count += r.alignments.length

// All alignments are packed
assert.equal(alignmentContainer.alignments.length, count)

// No duplicates
const seen = new Set()
for (let r of rows) {
for (let a of r.alignments) {
if (seen.has(a)) {
assert.fail(a, undefined, 'Alignment seen twice')
}
seen.add(a)
}
seen.add(a)
}
}

// No alignment overlaps
for (let r of rows) {
let lastEnd = -1
for (let a of r.alignments) {
assert.isAtLeast(a.start, lastEnd, 'Alignment start is < last end')
lastEnd = a.end
// No alignment overlaps
for (let r of rows) {
let lastEnd = -1
for (let a of r.alignments) {
assert.isAtLeast(a.start, lastEnd, 'Alignment start is < last end')
lastEnd = a.end
}
}
}


})


Expand Down
28 changes: 18 additions & 10 deletions test/testBAM.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import "./utils/mockObjects.js"
import BamReader from "../js/bam/bamReader.js"
import {assert} from 'chai'
import BamReaderNonIndexed from "../js/bam/bamReaderNonIndexed.js"
import {createGenome} from "./utils/Genome.js"


const genome = createGenome()

suite("testBAM", function () {

Expand All @@ -12,28 +16,32 @@ suite("testBAM", function () {
const end = 155160000

const bamReader = new BamReader({
type: 'bam',
url: 'test/data/bam/na12889.bam',
indexURL: 'test/data/bam/na12889.bam.csi'
})
type: 'bam',
url: 'test/data/bam/na12889.bam',
indexURL: 'test/data/bam/na12889.bam.csi'
},
genome)

const alignmentContainer = await bamReader.readAlignments(chr, start, end)
validate(assert, alignmentContainer)
})

test("BAM alignments - non indexed", async function () {

const chr = 'chr1'
const start = 155140000
const end = 155160000

const bamReader = new BamReaderNonIndexed({
type: 'bam',
url: 'test/data/bam/na12889.bam',
indexed: false
})
type: 'bam',
url: 'test/data/bam/na12889.bam',
indexed: false
},
genome)

const alignmentContainer = await bamReader.readAlignments(chr, start, end)
let alignmentContainer = await bamReader.readAlignments("chr1", start, end)
validate(assert, alignmentContainer)

alignmentContainer = await bamReader.readAlignments("1", start, end)
validate(assert, alignmentContainer)
})

Expand Down
2 changes: 1 addition & 1 deletion test/testBED.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {assert} from 'chai'
import {createGenome} from "./utils/Genome.js"

const genome = createGenome()
import GenomeUtils from "../js/genome/genomeUtils.js"
import Genome from "../js/genome/genome.js"

suite("testBed", function () {

Expand Down
61 changes: 26 additions & 35 deletions test/testChromAlias.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,35 @@ import {assert} from "chai"

suite("chromAlias", function () {

const genome = {
chromosomes: new Map([
["NC_007194.1", {name: "NC_007194.1", bpLength: 1}],
])
}

/**
* Test a UCSC style chrom alias flat file
*
* # refseq assembly genbank ncbi ucsc
* NC_007194.1 1 CM000169.1 1 chr1
* NC_007195.1 2 CM000170.1 2 chr2
* NC_007196.1 3 CM000171.1 3 chr3
* NC_007197.1 4 CM000172.1 4 chr4
* NC_007198.1 5 CM000173.1 5 chr5
* NC_007199.1 6 CM000174.1 6 chr6
* NC_007200.1 7 CM000175.1 7 chr7
* NC_007201.1 8 CM000176.1 8 chr8
*/
test("test chromAlias.txt", async function () {

const url = "test/data/genomes/t2t.chromAlias.txt"

const chromosomeNames = ["CP068254.1", "CP068255.2", "CP068256.2", "CP068257.2", "CP068258.2", "CP068259.2",
"CP068260.2", "CP068261.2", "CP068262.2", "CP068263.2", "CP068264.2", "CP068265.2", "CP068266.2",
"CP068267.2", "CP068268.2", "CP068269.2", "CP068270.2", "CP068271.2", "CP068272.2", "CP068273.2",
"CP068274.2", "CP068275.2", "CP068276.2", "CP068277.2", "CP086569.2"
]

const chromAlias = new ChromAliasFile(url, {})

await chromAlias.init(chromosomeNames)

const url = "test/data/genomes/GCF_000002655.1.chromAlias.txt"

const chromAlias = new ChromAliasFile(url, {}, genome)
const chromAliasRecord = await chromAlias.search("1")
assert.equal(chromAliasRecord.chr, "NC_007194.1")
assert.equal(chromAliasRecord.genbank, "CM000169.1")
assert.equal(chromAliasRecord.ncbi, "1")
assert.equal(chromAliasRecord.ucsc, "chr1")
})

test("test chromalias bb extra index search", async function () {
Expand All @@ -32,28 +46,6 @@ suite("chromAlias", function () {

const bbReader = new BWReader(config)


// There are 5 extra indexes, 1 for each alias
const ncbiName = "3"
const f1 = await bbReader.search(ncbiName)
assert.equal(ncbiName, f1.ncbi)

const ucscName = "chr2"
const f2 = await bbReader.search(ucscName)
assert.equal(ucscName, f2.ucsc)
})

test("test chromalias bb remote", async function () {
this.timeout(200000)
const config = {
url: "https://hgdownload.soe.ucsc.edu/hubs/GCA/009/914/755/GCA_009914755.4/GCA_009914755.4.chromAlias.bb",
format: "bigbed"
}

const bbReader = new BWReader(config)

const features = await bbReader.readFeatures("chr1")

// There are 5 extra indexes, 1 for each alias
const ncbiName = "3"
const f1 = await bbReader.search(ncbiName)
Expand All @@ -63,5 +55,4 @@ suite("chromAlias", function () {
const f2 = await bbReader.search(ucscName)
assert.equal(ucscName, f2.ucsc)
})
// chromAliasBbURL: "https://hgdownload.soe.ucsc.edu/hubs/GCA/009/914/755/GCA_009914755.4/GCA_009914755.4.chromAlias.bb",
})
Loading

0 comments on commit c7444ee

Please sign in to comment.