From 3a8bef26d35b0325e7eacea48c123d157528180b Mon Sep 17 00:00:00 2001 From: Dick Choi Date: Sat, 27 Aug 2016 12:23:58 +0900 Subject: [PATCH] add fixtures.TestDummy and transform method --- browser/lib/keygen.js | 2 +- browser/main/lib/dataApi/transform.js | 85 +++++++++++++ tests/dataApi/transform.js | 62 ++++++++++ tests/fixtures/TestDummy.js | 172 ++++++++++++++++++++++++++ 4 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 browser/main/lib/dataApi/transform.js create mode 100644 tests/dataApi/transform.js create mode 100644 tests/fixtures/TestDummy.js diff --git a/browser/lib/keygen.js b/browser/lib/keygen.js index 8b9fdf5b..f4937a83 100644 --- a/browser/lib/keygen.js +++ b/browser/lib/keygen.js @@ -2,6 +2,6 @@ const crypto = require('crypto') const _ = require('lodash') module.exports = function (length) { - if (!_.isFinite(length)) length = 6 + if (!_.isFinite(length)) length = 10 return crypto.randomBytes(length).toString('hex') } diff --git a/browser/main/lib/dataApi/transform.js b/browser/main/lib/dataApi/transform.js new file mode 100644 index 00000000..0a0f04cf --- /dev/null +++ b/browser/main/lib/dataApi/transform.js @@ -0,0 +1,85 @@ +const path = require('path') +const sander = require('sander') +const keygen = require('browser/lib/keygen') +const _ = require('lodash') +const CSON = require('season') + +function transform (storagePath) { + var boostnoteJSONPath = path.join(storagePath, 'boostnote.json') + return Promise.resolve() + .then(function readBoostnoteJSON () { + return sander.readFile(boostnoteJSONPath, { + encoding: 'utf-8' + }) + }) + .then(function verifyVersion (rawData) { + var boostnoteJSONData = JSON.parse(rawData) + if (boostnoteJSONData.version === '1.0') throw new Error('Target storage seems to be transformed already.') + if (!_.isArray(boostnoteJSONData.folders)) throw new Error('the value of folders is not an array.') + + return boostnoteJSONData + }) + .then(function setVersion (boostnoteJSONData) { + boostnoteJSONData.version = '1.0' + return sander.writeFile(boostnoteJSONPath, JSON.stringify(boostnoteJSONData)) + .then(() => boostnoteJSONData) + }) + .then(function fetchNotes (boostnoteJSONData) { + var fetchNotesFromEachFolder = boostnoteJSONData.folders + .map(function (folder) { + const folderDataJSONPath = path.join(storagePath, folder.key, 'data.json') + return sander + .readFile(folderDataJSONPath, { + encoding: 'utf-8' + }) + .then(function (rawData) { + var data = JSON.parse(rawData) + if (!_.isArray(data.notes)) throw new Error('value of notes is not an array.') + return data.notes + .map(function setFolderToNote (note) { + note.folder = folder.key + return note + }) + }) + .catch(function failedToReadDataJSON (err) { + console.warn('Failed to fetch notes from ', folderDataJSONPath, err) + return [] + }) + .then(function deleteFolderDir (data) { + sander.rimrafSync(path.join(storagePath, folder.key)) + return data + }) + }) + + return Promise.all(fetchNotesFromEachFolder) + .then(function flatten (folderNotes) { + return folderNotes + .reduce(function concatNotes (sum, notes) { + return sum.concat(notes) + }, []) + }) + }) + .then(function saveNotes (notes) { + notes.forEach(function renewKey (note) { + var newKey = keygen() + while (notes.some((_note) => _note.key === newKey)) { + newKey = keygen() + } + note.key = newKey + }) + + const noteDirPath = path.join(storagePath, 'notes') + notes + .map(function saveNote (note) { + CSON.writeFileSync(path.join(noteDirPath, note.key) + '.cson', note) + }) + return true + }) + .catch(function handleError (err) { + console.warn(err) + return false + }) +} + +module.exports = transform + diff --git a/tests/dataApi/transform.js b/tests/dataApi/transform.js new file mode 100644 index 00000000..fb54a582 --- /dev/null +++ b/tests/dataApi/transform.js @@ -0,0 +1,62 @@ +const test = require('ava') +const transform = require('browser/main/lib/dataApi/transform') + +global.document = require('jsdom').jsdom('') +global.window = document.defaultView +global.navigator = window.navigator + +const Storage = require('dom-storage') +const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const path = require('path') +const TestDummy = require('../fixtures/TestDummy') +const sander = require('sander') +const CSON = require('season') +const _ = require('lodash') +const os = require('os') + +const dummyStoragePath = path.join(os.tmpdir(), 'sandbox/transform-test-storage') + +test.beforeEach((t) => { + let dummyData = t.context.dummyData = TestDummy.dummyLegacyStorage(dummyStoragePath) + localStorage.setItem('storages', JSON.stringify([dummyData.cache])) +}) + +test.serial('Transform legacy storage into v1 storage', (t) => { + return Promise.resolve() + .then(function test () { + return transform(dummyStoragePath) + }) + .then(function assert (data) { + // Check the result. It must be true if succeed. + t.true(data) + + // Check all notes transformed. + let dummyData = t.context.dummyData + let noteDirPath = path.join(dummyStoragePath, 'notes') + let fileList = sander.readdirSync(noteDirPath) + let noteMap = fileList + .map((filePath) => { + return CSON.readFileSync(path.join(noteDirPath, filePath)) + }) + dummyData.notes + .forEach(function (targetNote) { + t.true(_.find(noteMap, {title: targetNote.title, folder: targetNote.folder}) != null) + }) + + // Check legacy folder directory is removed + dummyData.json.folders + .forEach(function (folder) { + try { + sander.statSync(dummyStoragePath, folder.key) + t.fail('Folder still remains. ENOENT error must be occured.') + } catch (err) { + t.is(err.code, 'ENOENT') + } + }) + }) +}) + +test.after.always(function () { + localStorage.clear() + sander.rimrafSync(dummyStoragePath) +}) diff --git a/tests/fixtures/TestDummy.js b/tests/fixtures/TestDummy.js new file mode 100644 index 00000000..449315b7 --- /dev/null +++ b/tests/fixtures/TestDummy.js @@ -0,0 +1,172 @@ +const faker = require('faker') +const keygen = require('browser/lib/keygen') +const _ = require('lodash') +const sander = require('sander') +const CSON = require('season') +const path = require('path') + +function dummyFolder (override = {}) { + var data = { + name: faker.lorem.word(), + color: faker.internet.color() + } + if (override.key == null) data.key = keygen() + + Object.assign(data, override) + + return data +} + +function dummyBoostnoteJSONData (override = {}, isLegacy = false) { + var data = {} + if (override.folders == null) { + data.folders = [] + + var folderCount = Math.floor((Math.random() * 5)) + 1 + for (var i = 0; i < folderCount; i++) { + var key = keygen() + while (data.folders.some((folder) => folder.key === key)) { + key = keygen() + } + + data.folders.push(dummyFolder({ + key + })) + } + } + if (!isLegacy) data.version = '1.0' + + Object.assign(data, override) + + return data +} + +function dummyNote (override = {}) { + var data = Math.random() > 0.5 + ? { + type: 'MARKDOWN_NOTE', + content: faker.lorem.lines() + } + : { + type: 'SNIPPET_NOTE', + description: faker.lorem.lines(), + snippets: [{ + name: faker.system.fileName(), + mode: 'text', + content: faker.lorem.lines() + }] + } + data.title = data.type === 'MARKDOWN_NOTE' + ? data.content.split('\n').shift() + : data.description.split('\n').shift() + data.createdAt = faker.date.past() + data.updatedAt = faker.date.recent() + data.isStarred = false + data.tags = faker.lorem.words().split(' ') + + if (override.key == null) data.key = keygen() + if (override.folder == null) data.folder = keygen() + Object.assign(data, override) + + return data +} + +/** + * @param {String} + * @param {Object} + * ``` + * { + * json: {folders: []}, + * cache: { + * key: String, + * name: String, + * type: String(enum:FILESYSTEM), + * path: String + * }, + * notes: [] + * } + * ``` + * @return {[type]} + */ +function dummyStorage (storagePath, override = {}) { + var jsonData = override.json != null + ? override.json + : dummyBoostnoteJSONData() + var cacheData = override.cache != null + ? override.cache + : {} + if (cacheData.key == null) cacheData.key = key + if (cacheData.name == null) cacheData.name = faker.random.word() + + sander.writeFileSync(path.join(storagePath, 'boostnote.json'), JSON.stringify(jsonData)) + var notesData = [] + console.log(notesData) + var noteCount = Math.floor((Math.random() * 15)) + 1 + for (var i = 0; i < noteCount; i++) { + var key = keygen() + while (notesData.some((note) => note.key === key)) { + key = keygen() + } + + var noteData = dummyNote({ + key, + folder: jsonData.folders[Math.floor(Math.random() * jsonData.folders.length)].key + }) + + notesData.push(noteData) + } + notesData.forEach(function saveNoteCSON (note) { + CSON.writeFileSync(path.join(storagePath, 'notes', note.key + '.cson'), _.omit(note, ['key'])) + }) + + return { + json: jsonData, + cache: cacheData, + notes: notesData + } +} + +function dummyLegacyStorage (storagePath, override = {}) { + var jsonData = override.json != null + ? override.json + : dummyBoostnoteJSONData({}, true) + var cacheData = override.cache != null + ? override.cache + : {} + if (cacheData.key == null) cacheData.key = key + if (cacheData.name == null) cacheData.name = faker.random.word() + + sander.writeFileSync(path.join(storagePath, 'boostnote.json'), JSON.stringify(jsonData)) + + for (var j = 0; j < jsonData.folders.length; j++) { + var noteCount = Math.floor((Math.random() * 5)) + 1 + var notesData = [] + for (var i = 0; i < noteCount; i++) { + var key = keygen(6) + while (notesData.some((note) => note.key === key)) { + key = keygen(6) + } + + var noteData = dummyNote({ + key, + folder: jsonData.folders[j].key + }) + notesData.push(noteData) + } + + CSON.writeFileSync(path.join(storagePath, jsonData.folders[j].key, 'data.json'), {notes: notesData.map((note) => _.omit(note, ['folder']))}) + } + + return { + json: jsonData, + cache: cacheData, + notes: notesData + } +} + +module.exports = { + dummyFolder, + dummyBoostnoteJSONData, + dummyStorage, + dummyLegacyStorage +}