Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation and basic unit tests for HEDVersion with libraries #1496

Merged
merged 9 commits into from
Aug 31, 2022
12 changes: 6 additions & 6 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: "monthly"
interval: 'monthly'

- package-ecosystem: "gitsubmodule"
directory: "/"
- package-ecosystem: 'gitsubmodule'
directory: '/'
schedule:
interval: "monthly"
interval: 'monthly'
2 changes: 1 addition & 1 deletion bids-validator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"date-fns": "^2.7.0",
"events": "^3.3.0",
"exifreader": "^4.1.0",
"hed-validator": "^3.7.1",
"hed-validator": "^3.8.0",
"ignore": "^4.0.2",
"is-utf8": "^0.2.1",
"jshint": "^2.9.6",
Expand Down
5 changes: 3 additions & 2 deletions bids-validator/src/files/deno.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const testDir = dirname(testPath)
const testFilename = basename(testPath)
const ignore = new FileIgnoreRulesDeno([])

Deno.test('Deno implementation of BIDSFile', async t => {
Deno.test('Deno implementation of BIDSFile', async (t) => {
await t.step('implements basic file properties', () => {
const file = new BIDSFileDeno(testDir, testFilename, ignore)
assertEquals(join(testDir, file.path), testPath)
Expand Down Expand Up @@ -45,7 +45,8 @@ Deno.test('Deno implementation of BIDSFile', async t => {
const bomFilename = 'bom-utf16.tsv'
const file = new BIDSFileDeno(bomDir, bomFilename, ignore)
await assertRejects(async () => file.text(), UnicodeDecodeError)
})
},
)
await t.step(
'strips BOM characters when reading UTF-8 via .text()',
async () => {
Expand Down
4 changes: 2 additions & 2 deletions bids-validator/src/files/tsv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export function parseTSV(contents: string) {
const rows: string[][] = normalizeEOL(contents)
.split('\n')
.filter(isContentfulRow)
.map(str => str.split('\t'))
.map((str) => str.split('\t'))
const headers = rows.length ? rows[0] : []

headers.map(x => (columns[x] = []))
headers.map((x) => (columns[x] = []))
for (let i = 1; i < rows.length; i++) {
for (let j = 0; j < headers.length; j++) {
columns[headers[j]].push(rows[i][j])
Expand Down
2 changes: 1 addition & 1 deletion bids-validator/src/tests/local/valid_dataset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { validatePath, formatAssertIssue } from './common.ts'

const PATH = 'tests/data/valid_dataset'

Deno.test('valid_dataset dataset', async t => {
Deno.test('valid_dataset dataset', async (t) => {
const { tree, result } = await validatePath(t, PATH)

await t.step('correctly ignores .bidsignore files', () => {
Expand Down
2 changes: 1 addition & 1 deletion bids-validator/src/tests/local/valid_filenames.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { validatePath, formatAssertIssue } from './common.ts'

const PATH = 'tests/data/valid_filenames'

Deno.test('valid_filenames dataset', async t => {
Deno.test('valid_filenames dataset', async (t) => {
const { tree, result } = await validatePath(t, PATH)

await t.step('correctly ignores .bidsignore files', () => {
Expand Down
2 changes: 1 addition & 1 deletion bids-validator/src/tests/local/valid_headers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { validatePath, formatAssertIssue } from './common.ts'

const PATH = 'tests/data/valid_headers'

Deno.test('valid_headers dataset', async t => {
Deno.test('valid_headers dataset', async (t) => {
const { tree, result } = await validatePath(t, PATH)

await t.step('correctly ignores .bidsignore files', () => {
Expand Down
108 changes: 108 additions & 0 deletions bids-validator/tests/events.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,77 @@ describe('Events', function () {
})
})

it('should not throw an issue if a value column is annotated', () => {
const events = [
{
file: { path: '/sub01/sub01_task-test_events.tsv' },
path: '/sub01/sub01_task-test_events.tsv',
contents:
'onset\tduration\ttest\tHED\n' + '7\t3.0\tone\tSpeed/30 mph\n',
},
]
const jsonDictionary = {
'/sub01/sub01_task-test_events.json': {
myCodes: {
test: {
HED: {
one: 'Label/#',
},
},
},
},
'/dataset_description.json': { HEDVersion: '8.0.0' },
}

return validate.Events.validateEvents(
events,
[],
headers,
jsonDictionary,
jsonFiles,
'',
).then((issues) => {
assert.deepStrictEqual(issues, [])
})
})

it('should not throw an issue if a library schema is included', () => {
const events = [
{
file: { path: '/sub01/sub01_task-test_events.tsv' },
path: '/sub01/sub01_task-test_events.tsv',
contents:
'onset\tduration\ttest\tHED\n' + '7\t3.0\tone\tSpeed/30 mph\n',
},
]

const jsonDictionary = {
'/sub01/sub01_task-test_events.json': {
myCodes: {
test: {
HED: {
one: 'ts:Sensory-presentation, Label/#',
},
},
},
},
'/dataset_description.json': {
HEDVersion: ['8.0.0', 'ts:testlib_1.0.2'],
},
}

return validate.Events.validateEvents(
events,
[],
headers,
jsonDictionary,
jsonFiles,
'',
).then((issues) => {
assert.deepStrictEqual(issues, [])
})
})

it('should throw an issue if the HED data is invalid', () => {
const events = [
{
Expand Down Expand Up @@ -218,6 +289,43 @@ describe('Events', function () {
})
})

it('should not throw an issue if multiple library schemas are included', () => {
const events = [
{
file: { path: '/sub01/sub01_task-test_events.tsv' },
path: '/sub01/sub01_task-test_events.tsv',
contents:
'onset\tduration\ttest\tHED\n' + '7\t3.0\tone\tSpeed/30 mph\n',
},
]

const jsonDictionary = {
'/sub01/sub01_task-test_events.json': {
myCodes: {
test: {
HED: {
one: 'ts:Sensory-presentation, Label/#, sc:Sleep-deprivation',
},
},
},
},
'/dataset_description.json': {
HEDVersion: ['8.0.0', 'ts:testlib_1.0.2', 'sc:score_0.0.1'],
},
}

return validate.Events.validateEvents(
events,
[],
headers,
jsonDictionary,
jsonFiles,
'',
).then((issues) => {
assert.deepStrictEqual(issues, [])
})
})

it('should properly issue warnings when appropriate', () => {
const events = [
{
Expand Down
36 changes: 17 additions & 19 deletions bids-validator/validators/events/hed.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import hedValidator from 'hed-validator'
import path from 'path'
import semver from 'semver'
import union from 'lodash/union'
import utils from '../../utils'
import parseTsv from '../tsv/tsvParser'
Expand All @@ -14,14 +12,24 @@ export default function checkHedStrings(events, jsonContents, jsonFiles, dir) {
if (!hedDataExists) {
return Promise.resolve([])
}
const dataset = new hedValidator.validator.BidsDataset(eventData, sidecarData)
const [schemaDefinition, schemaDefinitionIssues] = parseHedVersion(
jsonContents,

const datasetDescription = jsonContents['/dataset_description.json']
const datasetDescriptionData = new hedValidator.validator.BidsJsonFile(
'/dataset_description.json',
datasetDescription,
getSidecarFileObject('/dataset_description.json', jsonFiles),
)
const dataset = new hedValidator.validator.BidsDataset(
eventData,
sidecarData,
datasetDescriptionData,
dir,
)
// New stuff end does parseHedVersion need to be called anymore?
const schemaDefinitionIssues = parseHedVersion(jsonContents)
try {
return hedValidator.validator
.validateBidsDataset(dataset, schemaDefinition)
.validateBidsDataset(dataset)
.then((hedValidationIssues) => {
return schemaDefinitionIssues.concat(
convertHedIssuesToBidsIssues(hedValidationIssues),
Expand Down Expand Up @@ -99,24 +107,14 @@ function sidecarValueHasHed(sidecarValue) {
)
}

function parseHedVersion(jsonContents, dir) {
const schemaDefinition = {}
function parseHedVersion(jsonContents) {
const datasetDescription = jsonContents['/dataset_description.json']
const issues = []

if (!(datasetDescription && datasetDescription.HEDVersion)) {
issues.push(new Issue({ code: 109 }))
} else if (semver.valid(datasetDescription.HEDVersion)) {
schemaDefinition.version = datasetDescription.HEDVersion
return [new Issue({ code: 109 })]
} else {
schemaDefinition.path = path.join(
path.resolve(dir),
'sourcedata',
datasetDescription.HEDVersion,
)
return []
}

return [schemaDefinition, issues]
}

function internalHedValidatorIssue(error) {
Expand Down
4 changes: 2 additions & 2 deletions bids-validator/validators/json/schemas/pet.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
"items": { "type": "number" }
},
"CogAtlasID": { "$ref": "common_definitions.json#/definitions/CogAtlasID" },
"CogPOID": { "$ref": "common_definitions.json#/definitions/CogPOID" },
"CogPOID": { "$ref": "common_definitions.json#/definitions/CogPOID" },
"TaskName": {
"type": "string"
},
Expand All @@ -152,7 +152,7 @@
},
"Instructions": {
"$ref": "common_definitions.json#/definitions/Instructions"
}
}
},
"allOf": [
{
Expand Down