UNPKG

license-sniffer

Version:

Detect the license of node.js projects and their dependencies

370 lines (331 loc) 14.3 kB
var assert = require("assert"); var path = require("path"); var fs = require("fs"); var EOL = require("os").EOL; var mkdirp = require("mkdirp"); var temp = require("temp"); var duck = require("duck"); var licenseSniffer = require("../"); describe("license-sniffer.sniff", function() { this.timeout(5000); it("detects itself as BSD", function(done) { licenseSniffer.sniff(path.join(__dirname, ".."), function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["BSD"]); done(); }); }); it("uses license text from LICENSE when package.json specifies license", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { fs.writeFileSync( path.join(moduleDirPath, "package.json"), JSON.stringify({name: "test-module", license: "MIT"}) ); fs.writeFileSync(path.join(moduleDirPath, "LICENSE"), "The MIT license."); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.equal(license.text, "The MIT license."); done(); }); }); }); it("uses license template if package.json contains license but LICENSE does not exist", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { fs.writeFileSync( path.join(moduleDirPath, "package.json"), JSON.stringify({name: "test-module", license: "MIT"}) ); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); var expectedPrefix = "Copyright (c) 2014 test-module" + EOL + EOL + "Permission is hereby granted"; assert.equal(license.text.substring(0, expectedPrefix.length), expectedPrefix); done(); }); }); }); it("does not use license template if generate body is false", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { fs.writeFileSync( path.join(moduleDirPath, "package.json"), JSON.stringify({name: "test-module", license: "MIT"}) ); licenseSniffer.sniff(moduleDirPath, {generateBody: false}, function(err, license) { assert.ifError(err); assert.equal(license.text, null); done(); }); }); }); it("uses license alias to find license template", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { fs.writeFileSync( path.join(moduleDirPath, "package.json"), JSON.stringify({name: "test-module", license: "BSD"}) ); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); var expectedPrefix = "Copyright (c) 2014, test-module" + EOL + "All rights reserved."; assert.equal(license.text.substring(0, expectedPrefix.length), expectedPrefix); done(); }); }); }); it("errors if package.json doesn't exist", function(done) { licenseSniffer.sniff(__dirname, function(err, license) { assert.ok(err); done(); }); }); it("detects BSD license using LICENSE file if present", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { var bsdLicenseText = licenseText("bsd-2-clause"); fs.writeFileSync(path.join(moduleDirPath, "LICENSE"), bsdLicenseText); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["BSD 2-Clause"]); done(); }); }); }); it("detects MIT license using LICENSE file if present", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { var mitLicenseText = licenseText("mit"); fs.writeFileSync(path.join(moduleDirPath, "LICENSE"), mitLicenseText); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["MIT"]); done(); }); }); }); it("includes license text when detecting licence using LICENSE file", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { // Add a bit on the end to make sure we're actually reading from the module var bsdLicenseText = licenseText("bsd-2-clause") + "\n\n2-clause BSD"; fs.writeFileSync(path.join(moduleDirPath, "LICENSE"), bsdLicenseText); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.text, bsdLicenseText); done(); }); }); }); it("detects unlicense using UNLICENSE file if present", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { var unlicenseText = licenseText("unlicense"); fs.writeFile(path.join(moduleDirPath, "UNLICENSE"), unlicenseText); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["Public domain"]); done(); }); }); }); it("detects no license if LICENSE is not similar to any known license", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { fs.writeFile(path.join(moduleDirPath, "LICENSE"), "Been Listening"); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, []); done(); }); }); }); it("detects license text if included in README.md", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { fs.writeFile(path.join(moduleDirPath, "README.md"), "## License\n\n" + licenseText("mit")); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["MIT"]); done(); }); }); }); it("uses license text from README.md when package.json specifies license", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { fs.writeFileSync( path.join(moduleDirPath, "package.json"), JSON.stringify({name: "test-module", license: "MIT"}) ); fs.writeFileSync(path.join(moduleDirPath, "README.md"), "## License\n\nThe MIT license."); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.equal(license.text, "The MIT license."); done(); }); }); }); it("only considers text in README.md following 'License' header", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { var readmeJunk = new Array(1000).join("rabbit "); var readmeContents = "license\n\n## Introduction\n\n" + readmeJunk + "\n\n## License\n\n" + licenseText("mit"); fs.writeFile(path.join(moduleDirPath, "README.md"), readmeContents); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["MIT"]); done(); }); }); }); it("ignores text after license", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { var readmeJunk = new Array(1000).join("rabbit "); var readmeContents = "## License\n\n" + licenseText("mit") + "\n\n##The rest\n\n" + readmeJunk; fs.writeFile(path.join(moduleDirPath, "README.md"), readmeContents); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["MIT"]); done(); }); }); }); it("can find readme.md when not all uppercase", function(done) { withTemporaryModule("test-module", function(moduleDirPath) { fs.writeFile(path.join(moduleDirPath, "Readme.md"), "## License\n\n" + licenseText("mit")); licenseSniffer.sniff(moduleDirPath, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["MIT"]); done(); }); }); }); }); function licenseText(name) { return fs.readFileSync(path.join(__dirname, "../licenses/" + name), "utf8"); } function withTemporaryModule(moduleName, callback) { var moduleDirPath = temp.mkdirSync(); fs.writeFileSync( path.join(moduleDirPath, "package.json"), JSON.stringify({"name": moduleName}) ); callback(moduleDirPath); } describe("license-sniffer.sniffPackageJson", function() { it("reads license names as empty list if package.json is empty", function(done) { licenseSniffer.sniffPackageJson({}, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, []); done(); }); }); it("reads license field", function(done) { licenseSniffer.sniffPackageJson({license: "BSD"}, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["BSD"]); done(); }); }); it("packageJson is parsed to JSON object if its a string", function(done) { licenseSniffer.sniffPackageJson('{"license": "BSD"}', function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["BSD"]); done(); }); }); it("passes error to callback if JSON is badly formed", function(done) { licenseSniffer.sniffPackageJson('{license: "BSD"}', function(err, license) { assert.ok(err); done(); }); }); it("reads licenses field if license field is not present", function(done) { var packageJson = { licenses: [ { type: "BSD", url: "http://opensource.org/licenses/BSD-2-Clause" } ] }; licenseSniffer.sniffPackageJson(packageJson, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["BSD"]); done(); }); }); it("reads licenses field as array of strings if license field is not present", function(done) { var packageJson = { licenses: ["BSD"] }; licenseSniffer.sniffPackageJson(packageJson, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["BSD"]); done(); }); }); it("license field can be object", function(done) { var packageJson = { license: { type: "BSD", url: "http://opensource.org/licenses/BSD-2-Clause" } }; licenseSniffer.sniffPackageJson(packageJson, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["BSD"]); done(); }); }); it("reads multiple licenses if licenses has many elements", function(done) { var packageJson = { licenses: [{type: "BSD"}, {type: "MIT"}] }; licenseSniffer.sniffPackageJson(packageJson, function(err, license) { assert.ifError(err); assert.deepEqual(license.names, ["BSD", "MIT"]); done(); }); }); }); describe("license-sniffer.sniffRecursive", function() { it("sniffs licenses of modules in node_modules", function(done) { withTemporaryModule("test-module", function(modulePath) { writeFileSync( path.join(modulePath, "package.json"), JSON.stringify({name: "root", version: "0.1", license: "BSD"}) ); writeFileSync( path.join(modulePath, "node_modules/one/package.json"), JSON.stringify({name: "sub", version: "0.4", license: "MIT"}) ); writeFileSync( path.join(modulePath, "node_modules/one/node_modules/one-one/package.json"), JSON.stringify({name: "sub-sub", version: "1.4.5", license: "Apache"}) ); licenseSniffer.sniffRecursive(modulePath, function(err, result) { assert.ifError(err); assertThat(result, duck.isArray([ duck.hasProperties({ modulePath: modulePath, names: ["BSD"], dependencyChain: ["root@0.1"] }), duck.hasProperties({ modulePath: path.join(modulePath, "node_modules/one"), names: ["MIT"], dependencyChain: ["root@0.1", "sub@0.4"] }), duck.hasProperties({ modulePath: path.join(modulePath, "node_modules/one/node_modules/one-one"), names: ["Apache"], dependencyChain: ["root@0.1", "sub@0.4", "sub-sub@1.4.5"] }) ])); done(); }); }); }); }); function writeFileSync(filePath, contents) { mkdirp.sync(path.dirname(filePath)); fs.writeFileSync(filePath, contents); } function assertThat(value, matcher) { var result = matcher.matchesWithDescription(value); assert.ok(result.matches, result.description); }