Skip to content

Commit

Permalink
Merge pull request #485 from apiaryio/honzajavorek/prevent-nan-in-ann…
Browse files Browse the repository at this point in the history
…otations

Preventing NaN in printed annotations
  • Loading branch information
freaz committed May 17, 2016
2 parents cfd1e11 + 6deaf4c commit e842526
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 35 deletions.
33 changes: 19 additions & 14 deletions src/blueprint-utils.coffee
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
newlineRegExp = /\n/g

blueprintUtils = {}
NEWLINE_RE = /\n/g

blueprintUtils.characterIndexToPosition = (charIndex = 0, text = '') ->
pieceOfCode = text.substring 0, charIndex
return {
row: pieceOfCode.match(newlineRegExp)?.length + 1
}

characterIndexToPosition = (charIndex = 0, code = '') ->
codeFragment = code.substring(0, charIndex)
row = (codeFragment.match(NEWLINE_RE)?.length or 0) + 1
{row}

blueprintUtils.sortNumbersAscending = (a, b) ->

sortNumbersAscending = (a, b) ->
return a - b

blueprintUtils.warningLocationToRanges = (warningLocation = [], text = '') ->

warningLocationToRanges = (warningLocation = [], text = '') ->
unless warningLocation.length
# no start-end ranges, nothing to return
return []

rowsIndexes = []

position = blueprintUtils.characterIndexToPosition(warningLocation[0][0], text)
position = characterIndexToPosition(warningLocation[0][0], text)

# add this warning position row into ranges array
rowsIndexes.push position.row
Expand All @@ -29,10 +29,10 @@ blueprintUtils.warningLocationToRanges = (warningLocation = [], text = '') ->
if warningLocation.length > 0
# more lines
for loc, locKey in warningLocation when locKey > 0
position = blueprintUtils.characterIndexToPosition(loc[0], text)
position = characterIndexToPosition(loc[0], text)
rowsIndexes.push position.row

rowsIndexes.sort(blueprintUtils.sortNumbersAscending)
rowsIndexes.sort(sortNumbersAscending)
ranges = []
range = {start: rowsIndexes[0], end: rowsIndexes[0]}
for rowIndex in rowsIndexes
Expand All @@ -46,7 +46,7 @@ blueprintUtils.warningLocationToRanges = (warningLocation = [], text = '') ->
return ranges


blueprintUtils.rangesToLinesText = (ranges) ->
rangesToLinesText = (ranges) ->
pos = ''
for range, rangeIndex in ranges or []
if rangeIndex > 0
Expand All @@ -58,4 +58,9 @@ blueprintUtils.rangesToLinesText = (ranges) ->
return pos


module.exports = blueprintUtils
module.exports = {
characterIndexToPosition
sortNumbersAscending
warningLocationToRanges
rangesToLinesText
}
1 change: 0 additions & 1 deletion src/handle-runtime-problems.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ handleRuntimeProblems = (blueprintData) ->
error = false

for own filename, data of blueprintData
filename = data.filename
apiDescriptionDocument = data.raw

for annotation in data.annotations
Expand Down
17 changes: 11 additions & 6 deletions test/unit/blueprint-utils-test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ describe 'blueprintUtils', ->
options = {type: 'refract'}

describe 'characterIndexToPosition()', ->
str = null

it 'returns an object with non-zero-based row', ->
str = "first\nsecond\nthird lines\ncontent continues"
position = blueprintUtils.characterIndexToPosition str.indexOf('lines', str), str
assert.deepEqual position, {row: 3}
describe 'under standard circumstances', ->
it 'returns an object with non-zero-based row', ->
str = "first\nsecond\nthird lines\ncontent continues"
position = blueprintUtils.characterIndexToPosition str.indexOf('lines', str), str
assert.deepEqual position, {row: 3}

describe 'when given one-line input and zero index', ->
it 'returns an object with row 1', ->
str = "hello\n"
position = blueprintUtils.characterIndexToPosition str.indexOf('hello', str), str
assert.deepEqual position, {row: 1}

describe 'warningLocationToRanges()', ->
str = null
Expand Down
22 changes: 8 additions & 14 deletions test/unit/dredd-test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -407,10 +407,8 @@ describe 'Dredd class', () ->
assert.notOk dredd.runner.executeTransaction.called
done()


describe 'when Blueprint parsing error', () ->

before () ->
describe 'when Blueprint parsing error', ->
before ->
configuration =
url: 'http://localhost:3000/'
options:
Expand All @@ -435,9 +433,8 @@ describe 'Dredd class', () ->
assert.notOk dredd.runner.executeTransaction.called
done()

describe 'when Blueprint parsing warning', () ->

before () ->
describe 'when Blueprint parsing warning', ->
before ->
configuration =
url: 'http://localhost:3000/'
options:
Expand All @@ -464,10 +461,8 @@ describe 'Dredd class', () ->
assert.ok loggerStub.warn.called
done()


describe 'when non existing Blueprint path', () ->

beforeEach () ->
describe 'when non existing Blueprint path', ->
beforeEach ->
configuration =
url: 'http://localhost:3000/'
options:
Expand Down Expand Up @@ -515,9 +510,8 @@ describe 'Dredd class', () ->
assert.ok error
done()

describe 'when runtime contains any warning', () ->

beforeEach () ->
describe 'when runtime contains any warning', ->
beforeEach ->
configuration =
server: 'http://localhost:3000/'
options:
Expand Down
186 changes: 186 additions & 0 deletions test/unit/handle-runtime-problems-test.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@

{assert} = require('chai')
sinon = require('sinon')
proxyquire = require('proxyquire')
dreddTransactions = require('dredd-transactions')

logger = require('../../src/logger')
handleRuntimeProblems = proxyquire('../../src/handle-runtime-problems',
'./logger': logger
)


prepareData = (apiDescriptionDocument, filename, done) ->
dreddTransactions.compile(apiDescriptionDocument, filename, (err, {errors, warnings}) ->
return done(err) if err

annotations = []
for error in errors
error.type = 'error'
annotations.push(error)
for warning in warnings
warning.type = 'warning'
annotations.push(warning)

data = {}
data[filename] = {raw: apiDescriptionDocument, filename, annotations}

done(null, data)
)


describe('handleRuntimeProblems()', ->
warnOutput = undefined
errorOutput = undefined

beforeEach( ->
warnOutput = ''
errorOutput = ''

sinon.stub(logger, 'warn', (args...) ->
warnOutput += args.join(' ').toLowerCase()
)
sinon.stub(logger, 'error', (args...) ->
errorOutput += args.join(' ').toLowerCase()
)
)
afterEach( ->
logger.warn.restore()
logger.error.restore()
)

describe('Prints parser error', ->
error = undefined

apiDescriptionDocument = '''
FORMAT: 1A
# Beehive API
\t\t
'''
filename = 'dummy-filename.apib'

beforeEach((done) ->
prepareData(apiDescriptionDocument, filename, (err, data) ->
error = handleRuntimeProblems(data)
done()
)
)

it('returns error', ->
assert.ok(error)
)
it('has no warning output', ->
assert.equal(warnOutput, '')
)
it('has error output', ->
assert.ok(errorOutput)
)
context('the error output', ->
it('mentions it is from parser', ->
assert.include(errorOutput, 'parser')
)
it('mentions it is error', ->
assert.include(errorOutput, 'error')
)
it('mentions the filename', ->
assert.include(errorOutput, filename)
)
it('mentions the line', ->
assert.include(errorOutput, 'on line 3')
)
it('does not contain any NaNs', ->
assert.notInclude(errorOutput, 'nan')
)
)
)

describe('Prints parser warning', ->
error = undefined

apiDescriptionDocument = '''
FORMAT: 1A
# Beehive API
## Honey [/honey]
### Remove [DELETE]
+ Response
'''
filename = 'dummy-filename.apib'

beforeEach((done) ->
prepareData(apiDescriptionDocument, filename, (err, data) ->
error = handleRuntimeProblems(data)
done()
)
)

it('returns no error', ->
assert.notOk(error)
)
it('has no error output', ->
assert.equal(errorOutput, '')
)
it('has warning output', ->
assert.ok(warnOutput)
)
context('the warning output', ->
it('mentions it is from parser', ->
assert.include(warnOutput, 'parser')
)
it('mentions it is warning', ->
assert.include(warnOutput, 'warn')
)
it('mentions the filename', ->
assert.include(warnOutput, filename)
)
it('mentions the line', ->
assert.include(warnOutput, 'on line 5')
)
it('does not contain any NaNs', ->
assert.notInclude(warnOutput, 'nan')
)
)
)

describe('Prints warning about missing title', ->
error = undefined

apiDescriptionDocument = '''
So Long, and Thanks for All the Fish!
'''
filename = 'dummy-filename.apib'

beforeEach((done) ->
prepareData(apiDescriptionDocument, filename, (err, data) ->
error = handleRuntimeProblems(data)
done()
)
)

it('returns no error', ->
assert.notOk(error)
)
it('has no error output', ->
assert.equal(errorOutput, '')
)
it('has warning output', ->
assert.ok(warnOutput)
)
context('the warning output', ->
it('mentions it is from parser', ->
assert.include(warnOutput, 'parser')
)
it('mentions it is warning', ->
assert.include(warnOutput, 'warning')
)
it('mentions the filename', ->
assert.include(warnOutput, filename)
)
it('mentions the line', ->
assert.include(warnOutput, 'on line 1')
)
it('does not contain any NaNs', ->
assert.notInclude(warnOutput, 'nan')
)
)
)
)

0 comments on commit e842526

Please sign in to comment.