Merge remote-tracking branch 'refs/remotes/origin/master' into wl-electron-35

This commit is contained in:
Wliu
2015-12-18 20:02:22 -05:00
17 changed files with 345 additions and 337 deletions

View File

@@ -88,13 +88,13 @@ describe "DisplayBuffer", ->
describe "when there are korean characters", ->
it "takes them into account when finding the soft wrap column", ->
displayBuffer.setDefaultCharWidth(1, 0, 0, 10)
buffer.setText("1234세계를 향한 대화, 유니코 제10회유니코드국제")
buffer.setText("1234세계를향한대화,유니코제10회유니코드국제")
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe("1234세계를 ")
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe("향한 대화, ")
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe("니코 ")
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe("제10회유니")
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe("코드국")
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe("1234세계를")
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe("대화,")
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe("니코제10회")
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe("유니코드국")
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe("")
describe "when editor.softWrapAtPreferredLineLength is set", ->
it "uses the preferred line length as the soft wrap column when it is less than the configured soft wrap column", ->
@@ -130,8 +130,25 @@ describe "DisplayBuffer", ->
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe ' sort(left).concat(pivot).concat(sort(right));'
it "wraps the line at the first CJK character before the boundary", ->
displayBuffer.setEditorWidthInChars(10)
buffer.setTextInRange([[0, 0], [1, 0]], 'abcd efg유私フ业余爱\n')
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcd efg유私'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'フ业余爱'
buffer.setTextInRange([[0, 0], [1, 0]], 'abcd ef유gef业余爱\n')
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcd ef유'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'gef业余爱'
describe "when there is no whitespace before the boundary", ->
it "wraps the line exactly at the boundary since there's no more graceful place to wrap it", ->
it "wraps the line at the first CJK character before the boundary", ->
buffer.setTextInRange([[0, 0], [1, 0]], '私たちのabcdefghij\n')
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe '私たちの'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'abcdefghij'
it "wraps the line exactly at the boundary when no CJK character is found, since there's no more graceful place to wrap it", ->
buffer.setTextInRange([[0, 0], [1, 0]], 'abcdefghijklmnopqrstuvwxyz\n')
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcdefghij'

View File

@@ -9,61 +9,71 @@ describe "FileSystemBlobStore", ->
blobStore = FileSystemBlobStore.load(storageDirectory)
it "is empty when the file doesn't exist", ->
expect(blobStore.get("foo")).toBeUndefined()
expect(blobStore.get("bar")).toBeUndefined()
expect(blobStore.get("foo", "invalidation-key-1")).toBeUndefined()
expect(blobStore.get("bar", "invalidation-key-2")).toBeUndefined()
it "allows to read and write buffers from/to memory without persisting them", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
blobStore.set("foo", "invalidation-key-1", new Buffer("foo"))
blobStore.set("bar", "invalidation-key-2", new Buffer("bar"))
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("bar"))
expect(blobStore.get("foo", "invalidation-key-1")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar", "invalidation-key-2")).toEqual(new Buffer("bar"))
expect(blobStore.get("foo", "unexisting-key")).toBeUndefined()
expect(blobStore.get("bar", "unexisting-key")).toBeUndefined()
it "persists buffers when saved and retrieves them on load, giving priority to in-memory ones", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
blobStore.set("foo", "invalidation-key-1", new Buffer("foo"))
blobStore.set("bar", "invalidation-key-2", new Buffer("bar"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("bar"))
expect(blobStore.get("foo", "invalidation-key-1")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar", "invalidation-key-2")).toEqual(new Buffer("bar"))
expect(blobStore.get("foo", "unexisting-key")).toBeUndefined()
expect(blobStore.get("bar", "unexisting-key")).toBeUndefined()
blobStore.set("foo", new Buffer("changed"))
blobStore.set("foo", "new-key", new Buffer("changed"))
expect(blobStore.get("foo")).toEqual(new Buffer("changed"))
expect(blobStore.get("foo", "new-key")).toEqual(new Buffer("changed"))
expect(blobStore.get("foo", "invalidation-key-1")).toBeUndefined()
it "persists both in-memory and previously stored buffers when saved", ->
blobStore.set("foo", new Buffer("foo"))
blobStore.set("bar", new Buffer("bar"))
blobStore.set("foo", "invalidation-key-1", new Buffer("foo"))
blobStore.set("bar", "invalidation-key-2", new Buffer("bar"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
blobStore.set("bar", new Buffer("changed"))
blobStore.set("qux", new Buffer("qux"))
blobStore.set("bar", "invalidation-key-3", new Buffer("changed"))
blobStore.set("qux", "invalidation-key-4", new Buffer("qux"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("foo")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar")).toEqual(new Buffer("changed"))
expect(blobStore.get("qux")).toEqual(new Buffer("qux"))
expect(blobStore.get("foo", "invalidation-key-1")).toEqual(new Buffer("foo"))
expect(blobStore.get("bar", "invalidation-key-3")).toEqual(new Buffer("changed"))
expect(blobStore.get("qux", "invalidation-key-4")).toEqual(new Buffer("qux"))
expect(blobStore.get("foo", "unexisting-key")).toBeUndefined()
expect(blobStore.get("bar", "invalidation-key-2")).toBeUndefined()
expect(blobStore.get("qux", "unexisting-key")).toBeUndefined()
it "allows to delete keys from both memory and stored buffers", ->
blobStore.set("a", new Buffer("a"))
blobStore.set("b", new Buffer("b"))
blobStore.set("a", "invalidation-key-1", new Buffer("a"))
blobStore.set("b", "invalidation-key-2", new Buffer("b"))
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
blobStore.set("b", new Buffer("b"))
blobStore.set("c", new Buffer("c"))
blobStore.set("b", "invalidation-key-3", new Buffer("b"))
blobStore.set("c", "invalidation-key-4", new Buffer("c"))
blobStore.delete("b")
blobStore.delete("c")
blobStore.save()
blobStore = FileSystemBlobStore.load(storageDirectory)
expect(blobStore.get("a")).toEqual(new Buffer("a"))
expect(blobStore.get("b")).toBeUndefined()
expect(blobStore.get("c")).toBeUndefined()
expect(blobStore.get("a", "invalidation-key-1")).toEqual(new Buffer("a"))
expect(blobStore.get("b", "invalidation-key-2")).toBeUndefined()
expect(blobStore.get("b", "invalidation-key-3")).toBeUndefined()
expect(blobStore.get("c", "invalidation-key-4")).toBeUndefined()

1
spec/fixtures/native-cache/file-4.js vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = function () { return "file-4" }

View File

@@ -1,3 +1,7 @@
fs = require 'fs'
path = require 'path'
Module = require 'module'
describe "NativeCompileCache", ->
nativeCompileCache = require '../src/native-compile-cache'
[fakeCacheStore, cachedFiles] = []
@@ -5,39 +9,92 @@ describe "NativeCompileCache", ->
beforeEach ->
cachedFiles = []
fakeCacheStore = jasmine.createSpyObj("cache store", ["set", "get", "has", "delete"])
fakeCacheStore.has.andCallFake (cacheKey, invalidationKey) ->
fakeCacheStore.get(cacheKey, invalidationKey)?
fakeCacheStore.get.andCallFake (cacheKey, invalidationKey) ->
for entry in cachedFiles by -1
continue if entry.cacheKey isnt cacheKey
continue if entry.invalidationKey isnt invalidationKey
return entry.cacheBuffer
return
fakeCacheStore.set.andCallFake (cacheKey, invalidationKey, cacheBuffer) ->
cachedFiles.push({cacheKey, invalidationKey, cacheBuffer})
nativeCompileCache.setCacheStore(fakeCacheStore)
nativeCompileCache.setV8Version("a-v8-version")
nativeCompileCache.install()
it "writes and reads from the cache storage when requiring files", ->
fakeCacheStore.has.andReturn(false)
fakeCacheStore.set.andCallFake (filename, cacheBuffer) ->
cachedFiles.push({filename, cacheBuffer})
fn1 = require('./fixtures/native-cache/file-1')
fn2 = require('./fixtures/native-cache/file-2')
expect(cachedFiles.length).toBe(2)
expect(cachedFiles[0].filename).toBe(require.resolve('./fixtures/native-cache/file-1'))
expect(cachedFiles[0].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-1'))
expect(cachedFiles[0].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[0].cacheBuffer.length).toBeGreaterThan(0)
expect(fn1()).toBe(1)
expect(cachedFiles[1].filename).toBe(require.resolve('./fixtures/native-cache/file-2'))
expect(cachedFiles[1].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-2'))
expect(cachedFiles[1].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[1].cacheBuffer.length).toBeGreaterThan(0)
expect(fn2()).toBe(2)
fakeCacheStore.has.andReturn(true)
fakeCacheStore.get.andReturn(cachedFiles[0].cacheBuffer)
fakeCacheStore.set.reset()
delete Module._cache[require.resolve('./fixtures/native-cache/file-1')]
fn1 = require('./fixtures/native-cache/file-1')
expect(fakeCacheStore.set).not.toHaveBeenCalled()
expect(cachedFiles.length).toBe(2)
expect(fn1()).toBe(1)
it "deletes previously cached code when the cache is not valid", ->
describe "when v8 version changes", ->
it "updates the cache of previously required files", ->
nativeCompileCache.setV8Version("version-1")
fn4 = require('./fixtures/native-cache/file-4')
expect(cachedFiles.length).toBe(1)
expect(cachedFiles[0].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-4'))
expect(cachedFiles[0].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[0].cacheBuffer.length).toBeGreaterThan(0)
expect(fn4()).toBe("file-4")
nativeCompileCache.setV8Version("version-2")
delete Module._cache[require.resolve('./fixtures/native-cache/file-4')]
fn4 = require('./fixtures/native-cache/file-4')
expect(cachedFiles.length).toBe(2)
expect(cachedFiles[1].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-4'))
expect(cachedFiles[1].invalidationKey).not.toBe(cachedFiles[0].invalidationKey)
expect(cachedFiles[1].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[1].cacheBuffer.length).toBeGreaterThan(0)
describe "when a previously required and cached file changes", ->
beforeEach ->
fs.writeFileSync path.resolve('./spec/fixtures/native-cache/file-5'), """
module.exports = function () { return "file-5" }
"""
afterEach ->
fs.unlinkSync path.resolve('./spec/fixtures/native-cache/file-5')
it "removes it from the store and re-inserts it with the new cache", ->
fn5 = require('./fixtures/native-cache/file-5')
expect(cachedFiles.length).toBe(1)
expect(cachedFiles[0].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-5'))
expect(cachedFiles[0].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[0].cacheBuffer.length).toBeGreaterThan(0)
expect(fn5()).toBe("file-5")
delete Module._cache[require.resolve('./fixtures/native-cache/file-5')]
fs.appendFileSync(require.resolve('./fixtures/native-cache/file-5'), "\n\n")
fn5 = require('./fixtures/native-cache/file-5')
expect(cachedFiles.length).toBe(2)
expect(cachedFiles[1].cacheKey).toBe(require.resolve('./fixtures/native-cache/file-5'))
expect(cachedFiles[1].invalidationKey).not.toBe(cachedFiles[0].invalidationKey)
expect(cachedFiles[1].cacheBuffer).toBeInstanceOf(Uint8Array)
expect(cachedFiles[1].cacheBuffer.length).toBeGreaterThan(0)
it "deletes previously cached code when the cache is an invalid file", ->
fakeCacheStore.has.andReturn(true)
fakeCacheStore.get.andCallFake -> new Buffer("an invalid cache")

View File

@@ -136,14 +136,6 @@ describe "TextEditorPresenter", ->
# clearing additional rows won't trigger a state update
expectNoStateUpdate presenter, -> presenter.clearScreenRowsToMeasure()
expect(stateFn(presenter).tiles[0]).toBeDefined()
expect(stateFn(presenter).tiles[2]).toBeDefined()
expect(stateFn(presenter).tiles[4]).toBeDefined()
expect(stateFn(presenter).tiles[6]).toBeDefined()
expect(stateFn(presenter).tiles[8]).toBeUndefined()
expect(stateFn(presenter).tiles[10]).toBeDefined()
expect(stateFn(presenter).tiles[12]).toBeDefined()
# when another change triggers a state update we remove useless lines
expectStateUpdate presenter, -> presenter.setScrollTop(1)
@@ -625,23 +617,6 @@ describe "TextEditorPresenter", ->
expect(getState(presenter).hiddenInput.width).toBe 2
describe ".content", ->
describe ".scrollingVertically", ->
it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", ->
presenter = buildPresenter(scrollTop: 10, stoppedScrollingDelay: 200, explicitHeight: 100)
expect(getState(presenter).content.scrollingVertically).toBe true
advanceClock(300)
expect(getState(presenter).content.scrollingVertically).toBe false
expectStateUpdate presenter, -> presenter.setScrollTop(0)
expect(getState(presenter).content.scrollingVertically).toBe true
advanceClock(100)
expect(getState(presenter).content.scrollingVertically).toBe true
presenter.setScrollTop(10)
getState(presenter) # commits scroll position
advanceClock(100)
expect(getState(presenter).content.scrollingVertically).toBe true
expectStateUpdate presenter, -> advanceClock(100)
expect(getState(presenter).content.scrollingVertically).toBe false
describe ".maxHeight", ->
it "changes based on boundingClientRect", ->
presenter = buildPresenter(scrollTop: 0, lineHeight: 10)
@@ -807,6 +782,11 @@ describe "TextEditorPresenter", ->
getState(presenter) # commits scroll position
expect(editor.getFirstVisibleScreenRow()).toBe 6
it "updates when the model's scroll position is changed directly", ->
presenter = buildPresenter(scrollTop: 0, explicitHeight: 20, horizontalScrollbarHeight: 10, lineHeight: 10)
expectStateUpdate presenter, -> editor.setFirstVisibleScreenRow(1)
expect(getState(presenter).content.scrollTop).toBe 10
it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", ->
presenter = buildPresenter(scrollTop: 80, lineHeight: 10, explicitHeight: 50, horizontalScrollbarHeight: 0)
expect(getState(presenter).content.scrollTop).toBe(80)

View File

@@ -74,3 +74,23 @@ describe 'text utilities', ->
expect(textUtils.isKoreanCharacter("")).toBe(true)
expect(textUtils.isKoreanCharacter("O")).toBe(false)
describe ".isCJKCharacter(character)", ->
it "returns true when the character is either a korean, half-width or double-width character", ->
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isCJKCharacter("")).toBe(true)
expect(textUtils.isDoubleWidthCharacter("a")).toBe(false)
expect(textUtils.isDoubleWidthCharacter("O")).toBe(false)
expect(textUtils.isDoubleWidthCharacter("z")).toBe(false)

View File

@@ -26,8 +26,13 @@ describe "TokenizedBuffer", ->
describe "serialization", ->
describe "when the underlying buffer has a path", ->
it "deserializes it searching among the buffers in the current project", ->
beforeEach ->
buffer = atom.project.bufferForPathSync('sample.js')
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
it "deserializes it searching among the buffers in the current project", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
@@ -38,10 +43,25 @@ describe "TokenizedBuffer", ->
expect(tokenizedBufferB.buffer).toBe(tokenizedBufferA.buffer)
it "does not serialize / deserialize the current grammar", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
autoSelectedGrammar = tokenizedBufferA.grammar
tokenizedBufferA.setGrammar(atom.grammars.grammarForScopeName('source.coffee'))
tokenizedBufferB = TokenizedBuffer.deserialize(
JSON.parse(JSON.stringify(tokenizedBufferA.serialize())),
atom
)
expect(tokenizedBufferB.grammar).toBe(atom.grammars.grammarForScopeName('source.js'))
describe "when the underlying buffer has no path", ->
it "deserializes it searching among the buffers in the current project", ->
beforeEach ->
buffer = atom.project.bufferForPathSync(null)
it "deserializes it searching among the buffers in the current project", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
@@ -52,6 +72,38 @@ describe "TokenizedBuffer", ->
expect(tokenizedBufferB.buffer).toBe(tokenizedBufferA.buffer)
it "deserializes the previously selected grammar as soon as it's added when not available in the grammar registry", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
tokenizedBufferA.setGrammar(atom.grammars.grammarForScopeName("source.js"))
atom.grammars.removeGrammarForScopeName(tokenizedBufferA.grammar.scopeName)
tokenizedBufferB = TokenizedBuffer.deserialize(
JSON.parse(JSON.stringify(tokenizedBufferA.serialize())),
atom
)
expect(tokenizedBufferB.grammar).not.toBeFalsy()
expect(tokenizedBufferB.grammar).not.toBe(tokenizedBufferA.grammar)
atom.grammars.addGrammar(tokenizedBufferA.grammar)
expect(tokenizedBufferB.grammar).toBe(tokenizedBufferA.grammar)
it "deserializes the previously selected grammar on construction when available in the grammar registry", ->
tokenizedBufferA = new TokenizedBuffer({
buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert
})
tokenizedBufferA.setGrammar(atom.grammars.grammarForScopeName("source.js"))
tokenizedBufferB = TokenizedBuffer.deserialize(
JSON.parse(JSON.stringify(tokenizedBufferA.serialize())),
atom
)
expect(tokenizedBufferB.grammar).toBe(tokenizedBufferA.grammar)
describe "when the buffer is destroyed", ->
beforeEach ->
buffer = atom.project.bufferForPathSync('sample.js')