From 5453a0cbf81e0950695f55a155e9bef0864df940 Mon Sep 17 00:00:00 2001 From: Ethan Davis Date: Mon, 18 Mar 2019 21:19:49 -0700 Subject: [PATCH] Non-immediate: Add map type and associated tests. --- lib/protospec.js | 16 +++++++++++ lib/types.js | 2 +- lib/types/map.js | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ test.js | 52 ++++++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 lib/types/map.js diff --git a/lib/protospec.js b/lib/protospec.js index 6844889..94de3cd 100644 --- a/lib/protospec.js +++ b/lib/protospec.js @@ -58,6 +58,22 @@ const importAll = (data) => { options.of = parsedSchemas[options.of] } + if (options.hasOwnProperty('key')) { + if (!types.hasOwnProperty(options.key)) throw new Error('Type \'' + options.key + '\' does not exist. (:' + i + ')') + + options.key = { + 'type': types[options.key] + } + } + + if (options.hasOwnProperty('value')) { + if (!types.hasOwnProperty(options.value)) throw new Error('Type \'' + options.value + '\' does not exist. (:' + i + ')') + + options.value = { + 'type': types[options.value] + } + } + Object.assign(elementDefinition, options) } diff --git a/lib/types.js b/lib/types.js index 2ebe5a1..3661193 100644 --- a/lib/types.js +++ b/lib/types.js @@ -3,7 +3,7 @@ const fs = require('fs') const types = {} -const typeNames = ['int', 'uint', 'varint', 'float', 'double', 'boolean', 'string', 'buffer', 'list', 'instance'] +const typeNames = ['int', 'uint', 'varint', 'float', 'double', 'boolean', 'string', 'buffer', 'list', 'map', 'instance'] for (let i = 0; i < typeNames.length; i++) { types[typeNames[i]] = require(path.join(__dirname, 'types', typeNames[i] + '.js')) diff --git a/lib/types/map.js b/lib/types/map.js new file mode 100644 index 0000000..bc548e0 --- /dev/null +++ b/lib/types/map.js @@ -0,0 +1,72 @@ +const path = require('path') + +const Schema = require(path.join(__dirname, '..', '..', 'model', 'Schema.js')) +const list = require(path.join(__dirname, 'list.js')) + +const schemaCache = new Map() + +const genMapSchema = (data) => { + if (schemaCache.has(data)) { + return schemaCache.get(data) + } + else { + const generated = new Schema([ + { + 'name': 'pairs', + 'type': list, + 'of': new Schema([ + Object.assign(data.key, { + 'name': 'key' + }), + Object.assign(data.value, { + 'name': 'value' + }) + ]) + } + ]) + + schemaCache.set(data, generated) + + return generated + } +} + +module.exports = { + 'parse': (buf, from, data) => { + if (buf.length - from < 1) { + return { + 'hadUnderflow': true + } + } + + const mapSchema = genMapSchema(data) + + const parseResult = mapSchema.parse(buf, from, { + 'returnDetails': true + }) + + if (parseResult.hadUnderflow) { + return { + 'hadUnderflow': true + } + } + + const parsedMap = new Map(parseResult.data.pairs.map((pair) => [pair.key, pair.value])) + + return { + 'readBytes': parseResult.finishedIndex - from, + 'data': parsedMap, + 'hadUnderflow': false + } + }, + 'serialize': (value, data) => { + const mapSchema = genMapSchema(data) + + return mapSchema.build({ + 'pairs': Array.from(value).map((entry) => new Object({ + 'key': entry[0], + 'value': entry[1] + })) + }) + } +} \ No newline at end of file diff --git a/test.js b/test.js index 4bf7aee..a20c3fa 100644 --- a/test.js +++ b/test.js @@ -330,6 +330,58 @@ w.add('Instance type functionality', (result) => { result(true, 'Validated built data.') }) +w.add('Map type functionality', (result) => { + const mapSchema = new Schema([ + { + 'name': 'info', + 'type': types.map, + 'key': { + 'type': types.string + }, + 'value': { + 'type': types.string + } + } + ]) + + const testData = { + 'info': new Map([ + ['name', 'Person A'], + ['location', 'Earth'], + ['status', 'online'] + ]) + } + + const built = mapSchema.build(testData) + + assert.deepStrictEqual(testData, mapSchema.parse(built)) + + result(true, 'Validated built data.') +}) + +w.add('Map protospec functionality', (result) => { + const mapSchema = protospec.importAll(` + + def infoData + map info key=string;value=string + + `).infoData + + const testData = { + 'info': new Map([ + ['name', 'Person A'], + ['location', 'Earth'], + ['status', 'online'] + ]) + } + + const built = mapSchema.build(testData) + + assert.deepStrictEqual(testData, mapSchema.parse(built)) + + result(true, 'Validated built data. (Protospec success!)') +}) + w.test() process.stdin.on('data', () => {}) \ No newline at end of file