| @@ -14,6 +14,7 @@ | |||||
| }, | }, | ||||
| "homepage": "https://github.com/VCVRack/community#readme", | "homepage": "https://github.com/VCVRack/community#readme", | ||||
| "devDependencies": { | "devDependencies": { | ||||
| "ajv": "^5.5.2", | |||||
| "jasmine": "^2.8.0", | "jasmine": "^2.8.0", | ||||
| "node-virustotal": "^2.4.2", | "node-virustotal": "^2.4.2", | ||||
| "request": "^2.83.0" | "request": "^2.83.0" | ||||
| @@ -0,0 +1,27 @@ | |||||
| # Jasmine Tests | |||||
| [Jasmine Intro](https://jasmine.github.io/2.8/introduction.html) | |||||
| To run all tests: | |||||
| ``` | |||||
| npm test | |||||
| ``` | |||||
| To run only the zip tests for example: | |||||
| ``` | |||||
| ./node_modules/.bin/jasmine --filter=zip | |||||
| ``` | |||||
| # Virus Total | |||||
| **Rate Limit: 4 per minute** | |||||
| `VT_API_KEY` env var is required and already set in travisci settings | |||||
| [Public API](https://www.virustotal.com/en/documentation/public-api/v2/) | |||||
| [Node Module](https://github.com/natewatson999/node-virustotal) | |||||
| @@ -0,0 +1,59 @@ | |||||
| const CUR_VER_PREFIX = '0.5'; | |||||
| const fs = require("fs"); | |||||
| const Ajv = require('ajv'); //https://github.com/epoberezkin/ajv | |||||
| const ajv = new Ajv({}); | |||||
| const validate = ajv.compile(require('./manifest.json')); | |||||
| describe("json", function() { | |||||
| it("manifest files should be valid against the schema", function(done) { | |||||
| fs.readdir('plugins', function(err, files) { | |||||
| if (err){ | |||||
| fail("unable to read plugins dir"); | |||||
| } | |||||
| for (let index in files) { | |||||
| const fileName = files[index]; | |||||
| const filePath = `plugins/${fileName}`; | |||||
| if(!filePath.toLowerCase().endsWith('.json')){ | |||||
| fail("manifests should have .json extension"); | |||||
| } | |||||
| fs.readFile(filePath, 'utf8', (err, fileContent) => { | |||||
| if (err){ | |||||
| fail("unable to read manifest file"); | |||||
| } | |||||
| let manifestObj; | |||||
| try { | |||||
| const obj = JSON.parse(fileContent); | |||||
| const valid = validate(obj); | |||||
| if (!valid) { | |||||
| validate.errors.map(e=>e.message+=` in ${filePath}`) | |||||
| fail(validate.errors); | |||||
| } | |||||
| if(!(/^[a-zA-Z0-9_\-]*$/).test(obj.slug)){ | |||||
| fail(`slug does not match regex in ${filePath}`); | |||||
| } | |||||
| if(fileName.replace('.json','') !== obj.slug){ | |||||
| fail(`slug '${obj.slug}' does not match fileName: ${fileName}`); | |||||
| } | |||||
| if(obj.version && !obj.version.startsWith(CUR_VER_PREFIX)){ | |||||
| fail(`version '${obj.version}' must start with '${CUR_VER_PREFIX}'`); | |||||
| } | |||||
| done(); | |||||
| } catch(err){ | |||||
| fail(`Invalid JSON: ${filePath}\n${err}`); | |||||
| } | |||||
| }); | |||||
| } | |||||
| }); | |||||
| }); | |||||
| }); | |||||
| @@ -1,35 +0,0 @@ | |||||
| //Jasmine Test - https://jasmine.github.io/2.8/introduction.html | |||||
| const fs = require("fs"); | |||||
| describe("json", function() { | |||||
| it("manifest files should be valid parsable json", function(done) { | |||||
| fs.readdir('plugins', function(err, files) { | |||||
| if (err){ | |||||
| fail("unable to read plugins dir"); | |||||
| } | |||||
| for (let index in files) { | |||||
| const filePath = `plugins/${files[index]}`; | |||||
| if(!filePath.toLowerCase().endsWith('.json')){ | |||||
| fail("manifests should have .json extension"); | |||||
| } | |||||
| fs.readFile(filePath, 'utf8', (err, fileContent) => { | |||||
| if (err){ | |||||
| fail("unable to read manifest file"); | |||||
| } | |||||
| let manifestObj; | |||||
| try { | |||||
| manifestObj = JSON.parse(fileContent); | |||||
| done(); | |||||
| } catch(err){ | |||||
| fail(`Invalid JSON: ${filePath}\n${err}`); | |||||
| } | |||||
| }); | |||||
| } | |||||
| }); | |||||
| }); | |||||
| }); | |||||
| @@ -0,0 +1,100 @@ | |||||
| { | |||||
| "id": "manifest.json", | |||||
| "type": "object", | |||||
| "required": [ | |||||
| "slug", | |||||
| "version" | |||||
| ], | |||||
| "description": "A plugin manifest file for VCV Rack.", | |||||
| "properties": { | |||||
| "slug": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "name": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "author": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "license": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "version": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "homepage": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "donation": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "manual": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "source": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "disabled": { | |||||
| "type": "boolean", | |||||
| "description": "used when a plugin needs to be disabled" | |||||
| }, | |||||
| "productId": { | |||||
| "type": "number", | |||||
| "description": "only used by vcv rack website" | |||||
| }, | |||||
| "downloads": { | |||||
| "type": "object", | |||||
| "properties": { | |||||
| "win": { | |||||
| "type": "object", | |||||
| "properties": { | |||||
| "download": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "sha256": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| } | |||||
| } | |||||
| }, | |||||
| "lin": { | |||||
| "type": "object", | |||||
| "properties": { | |||||
| "download": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "sha256": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| } | |||||
| } | |||||
| }, | |||||
| "mac": { | |||||
| "type": "object", | |||||
| "properties": { | |||||
| "download": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| }, | |||||
| "sha256": { | |||||
| "type": "string", | |||||
| "description": "" | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| }, | |||||
| "additionalProperties": false | |||||
| } | |||||