| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- require 'test_helper'
- require 'docs'
- class DocsAbstractStoreTest < MiniTest::Spec
- InvalidPathError = Docs::AbstractStore::InvalidPathError
- LockError = Docs::AbstractStore::LockError
- let :path do
- '/'
- end
- let :store do
- Docs::AbstractStore.new(@path || path).tap do |store|
- store.extend FakeInstrumentation
- end
- end
- describe ".new" do
- it "raises an error with a relative path" do
- assert_raises ArgumentError do
- Docs::AbstractStore.new 'path'
- end
- end
- it "sets #root_path" do
- @path = '/path'
- assert_equal @path, store.root_path
- end
- it "expands #root_path" do
- @path = '/path/..'
- assert_equal '/', store.root_path
- end
- it "sets #working_path" do
- assert_equal store.root_path, store.working_path
- end
- end
- describe "#root_path" do
- it "can't be overwritten" do
- @path = '/path'
- store.root_path << '/..'
- assert_equal '/path', store.root_path
- end
- end
- describe "#working_path" do
- it "can't be overwritten" do
- @path = '/path'
- store.working_path << '/..'
- assert_equal '/path', store.working_path
- end
- end
- describe "#open" do
- it "raises an error when the store is locked" do
- assert_raises LockError do
- store.send :lock, &-> { store.open 'dir' }
- end
- end
- context "with a relative path" do
- it "updates #working_path relative to #root_path" do
- 2.times { store.open 'dir' }
- assert_equal File.join(path, 'dir'), store.working_path
- end
- it "expands the new #working_path" do
- store.open './dir/../'
- assert_equal path, store.working_path
- end
- it "raises an error when the new #working_path is outside of #root_path" do
- @path = '/dir'
- assert_raises InvalidPathError do
- store.open '../dir2'
- end
- end
- end
- context "with an absolute path" do
- it "updates #working_path" do
- store.open File.join(path, 'dir')
- assert_equal File.join(path, 'dir'), store.working_path
- end
- it "expands the new #working_path" do
- store.open File.join(path, 'dir/..')
- assert_equal path, store.working_path
- end
- it "raises an error when the new #working_path is outside of #root_path" do
- @path = '/dir'
- assert_raises InvalidPathError do
- store.open '/dir2'
- end
- end
- end
- context "with a block" do
- it "calls the block" do
- store.open('dir') { @called = true }
- assert @called
- end
- it "returns the block's return value" do
- assert_equal 1, store.open('dir') { 1 }
- end
- it "updates #working_path while calling the block" do
- store.open 'dir' do
- assert_equal File.join(path, 'dir'), store.working_path
- end
- end
- it "resets #working_path to its previous value afterward" do
- store.open('dir')
- store.open('dir2') {}
- assert_equal File.join(path, 'dir'), store.working_path
- end
- it "resets #working_path even when the block fails" do
- assert_raises RuntimeError do
- store.open('dir') { raise }
- end
- assert_equal path, store.working_path
- end
- end
- end
- describe "#close" do
- it "resets #working_path to #root_path" do
- 2.times { store.open 'dir' }
- store.close
- assert_equal path, store.working_path
- end
- it "raises an error when the store is locked" do
- assert_raises LockError do
- store.send :lock, &-> { store.close }
- end
- end
- end
- describe "#expand_path" do
- context "when #working_path is '/'" do
- before do
- store.open '/'
- end
- it "returns '/path' with './path'" do
- assert_equal '/path', store.expand_path('./path')
- end
- it "returns '/path' with '/path'" do
- assert_equal '/path', store.expand_path('/path')
- end
- end
- context "when #working_path is '/dir'" do
- before do
- store.open '/dir'
- end
- it "returns '/dir/path' with './path'" do
- assert_equal '/dir/path', store.expand_path('./path')
- end
- it "returns '/dir/path' with 'path/../path'" do
- assert_equal '/dir/path', store.expand_path('path/../path')
- end
- it "returns '/dir/path' with '/dir/path'" do
- assert_equal '/dir/path', store.expand_path('/dir/path')
- end
- it "raises an error with '..'" do
- assert_raises InvalidPathError do
- store.expand_path '..'
- end
- end
- it "raises an error with '/'" do
- assert_raises InvalidPathError do
- store.expand_path '/'
- end
- end
- end
- end
- describe "#read" do
- it "raises an error with a path outside of #working_path" do
- @path = '/path'
- assert_raises InvalidPathError do
- store.read '../file'
- end
- end
- it "returns nil when the file doesn't exist" do
- dont_allow(store).read_file
- stub(store).file_exist?('/file') { false }
- assert_nil store.read('file')
- end
- it "returns #read_file when the file exists" do
- stub(store).read_file('/file') { 1 }
- stub(store).file_exist?('/file') { true }
- assert_equal 1, store.read('file')
- end
- end
- describe "#write" do
- it "raises an error with a path outside of #working_path" do
- @path = '/path'
- assert_raises InvalidPathError do
- store.write '../file', ''
- end
- end
- context "when the file doesn't exist" do
- before do
- stub(store).file_exist?('/file') { false }
- stub(store).create_file
- end
- it "returns #create_file" do
- stub(store).create_file('/file', '') { 1 }
- assert_equal 1, store.write('file', '')
- end
- it "instrument 'create'" do
- store.write 'file', ''
- assert store.last_instrumentation
- assert_equal 'create.store', store.last_instrumentation[:event]
- assert_equal '/file', store.last_instrumentation[:payload][:path]
- end
- end
- context "when the file exists" do
- before do
- stub(store).file_exist?('/file') { true }
- stub(store).update_file
- end
- it "returns #update_file" do
- stub(store).update_file('/file', '') { 1 }
- assert_equal 1, store.write('file', '')
- end
- it "instruments 'update'" do
- store.write 'file', ''
- assert store.last_instrumentation
- assert_equal 'update.store', store.last_instrumentation[:event]
- assert_equal '/file', store.last_instrumentation[:payload][:path]
- end
- end
- end
- describe "#delete" do
- it "raises an error with a path outside og #working_path" do
- @path = '/path'
- assert_raises InvalidPathError do
- store.delete '../file'
- end
- end
- it "returns nil when the file doesn't exist" do
- dont_allow(store).delete_file
- stub(store).file_exist?('/file') { false }
- assert_nil store.delete('file')
- end
- context "when the file exists" do
- before do
- stub(store).file_exist?('/file') { true }
- stub(store).delete_file
- end
- it "calls #delete_file" do
- mock(store).delete_file('/file')
- store.delete 'file'
- end
- it "returns true" do
- assert store.delete('file')
- end
- it "instruments 'destroy'" do
- store.delete 'file'
- assert store.last_instrumentation
- assert_equal 'destroy.store', store.last_instrumentation[:event]
- assert_equal '/file', store.last_instrumentation[:payload][:path]
- end
- end
- end
- describe "exist?" do
- it "raises an error with a path outside of #working_path" do
- @path = '/path'
- assert_raises InvalidPathError do
- store.exist? '../file'
- end
- end
- it "returns #file_exist?" do
- stub(store).file_exist?('/file') { 1 }
- assert_equal 1, store.exist?('file')
- end
- end
- describe "mtime" do
- it "raises an error with a path outside of #working_path" do
- @path = '/path'
- assert_raises InvalidPathError do
- store.mtime '../file'
- end
- end
- it "returns nil when the file doesn't exist" do
- stub(store).file_exist?('/file') { false }
- dont_allow(store).file_mtime
- assert_nil store.mtime('file')
- end
- it "returns #file_mtime when the file exists" do
- stub(store).file_exist?('/file') { true }
- stub(store).file_mtime('/file') { 1 }
- assert_equal 1, store.mtime('file')
- end
- end
- describe "#size" do
- it "raises an error with a path outside of #working_path" do
- @path = '/path'
- assert_raises InvalidPathError do
- store.size '../file'
- end
- end
- it "returns nil when the file doesn't exist" do
- stub(store).file_exist?('/file') { false }
- dont_allow(store).file_size
- assert_nil store.size('file')
- end
- it "returns #file_size when the file exists" do
- stub(store).file_exist?('/file') { true }
- stub(store).file_size('/file') { 1 }
- assert_equal 1, store.size('file')
- end
- end
- describe "#each" do
- it "calls #list_files with #working_path" do
- store.open 'dir'
- block = Proc.new {}
- mock(store).list_files(File.join(path, 'dir'), &block)
- store.each(&block)
- end
- end
- describe "#replace" do
- before do
- stub(store).file_exist?
- stub(store).create_file
- stub(store).delete_file
- end
- def stub_paths(*paths)
- stub(store).each { |block| paths.each(&block) }
- end
- it "calls the block" do
- store.replace { @called = true }
- assert @called
- end
- it "returns the block's return value" do
- assert_equal 1, store.replace { 1 }
- end
- it "locks the store while calling the block" do
- assert_raises LockError do
- store.replace { store.open('dir') }
- end
- store.open 'dir'
- end
- context "with a path" do
- it "opens the path while calling the block" do
- store.replace 'dir' do
- assert_equal File.join(path, 'dir'), store.working_path
- end
- end
- end
- context "when the block writes no files" do
- it "doesn't delete files" do
- stub_paths '/', '/file'
- dont_allow(store).delete_file
- store.replace {}
- end
- end
- context "when the block writes files" do
- it "deletes untouched files" do
- stub_paths '/', '/dir', '/dir/file', '/dir/file2', '/dir2'
- mock(store).delete_file('/dir/file2').then.delete_file('/dir2')
- store.replace { store.write 'dir/file', '' }
- end
- it "doesn't delete touched files" do
- stub_paths '/', '/dir', '/dir/(file)'
- dont_allow(store).delete_file
- store.replace { store.write 'dir/(file)', '' }
- end
- end
- context "when the block fails" do
- it "doesn't delete files" do
- stub_paths '/', '/file'
- dont_allow(store).delete_file
- assert_raises RuntimeError do
- store.replace { store.write 'file2', ''; raise }
- end
- end
- it "unlocks the store afterward" do
- assert_raises RuntimeError do
- store.replace { raise }
- end
- store.open 'dir'
- end
- end
- context "when called multiple times" do
- before do
- stub_paths '/', '/file'
- end
- it "deletes untouched files that were touched the previous time" do
- store.replace { store.write 'file', '' }
- mock(store).delete_file '/file'
- store.replace { store.write 'file2', '' }
- end
- it "deletes untouched files that were touched and failed the previous time" do
- assert_raises RuntimeError do
- store.replace { store.write 'file', ''; raise }
- end
- mock(store).delete_file '/file'
- store.replace { store.write 'file2', '' }
- end
- end
- end
- end
|