diff --git a/features/attachments.feature b/features/attachments.feature index e8649a2eb..0b283773a 100644 --- a/features/attachments.feature +++ b/features/attachments.feature @@ -19,7 +19,13 @@ Feature: Attachments """ var hooks = function () { this.Before(function(scenario, callback) { - scenario.attach(new Buffer([100, 97, 116, 97]), 'image/png'); + var data = []; + + for (var i = 0; i < 256; i++) { + data.push(i); + } + + scenario.attach(new Buffer(data), 'image/png'); callback(); }); }; @@ -57,7 +63,7 @@ Feature: Attachments "embeddings": [ { "mime_type": "image/png", - "data": "ZGF0YQ==" + "data": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==" } ] }, @@ -98,14 +104,25 @@ Feature: Attachments var hooks = function () { this.Before(function(scenario, callback) { var Stream = require('stream'); - var versionParts = /v(\d+)\.(\d+)\.(\d+)/.exec(process.version); - var major = parseInt(versionParts[0], 10); - var minor = parseInt(versionParts[1], 10); + var versionParts = process.version.match(/v(\d+)\.(\d+)\.(\d+)/); + var major = parseInt(versionParts[1], 10); + var minor = parseInt(versionParts[2], 10); + var data1 = []; + var data2 = []; + + for (var i = 0; i < 128; i++) { + data1.push(i); + } + + for (var i = 128; i < 256; i++) { + data2.push(i); + } if (major > 0 || minor >= 10) { var stream = new Stream.Readable(); stream._read = function() {}; - stream.push(new Buffer([100, 97, 116, 97])); + stream.push(new Buffer(data1)); + stream.push(new Buffer(data2)); stream.push(null); scenario.attach(stream, 'image/png', function(error) { @@ -113,7 +130,7 @@ Feature: Attachments }); } else { - scenario.attach(new Buffer([100, 97, 116, 97]), 'image/png'); + scenario.attach(new Buffer([].concat(data1, data2)), 'image/png'); callback(); } }); @@ -152,7 +169,7 @@ Feature: Attachments "embeddings": [ { "mime_type": "image/png", - "data": "ZGF0YQ==" + "data": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==" } ] }, diff --git a/lib/cucumber/api/scenario.js b/lib/cucumber/api/scenario.js index bec8b27e4..f61fd9533 100644 --- a/lib/cucumber/api/scenario.js +++ b/lib/cucumber/api/scenario.js @@ -23,9 +23,9 @@ var Scenario = function (astTreeWalker, astScenario) { data.on('data', function(chunk) { buffers.push(chunk); - }) + }); data.on('end', function() { - astTreeWalker.attach(Buffer.concat(buffers).toString(), mimeType); + astTreeWalker.attach(Buffer.concat(buffers).toString('binary'), mimeType); callback(); }); @@ -34,18 +34,16 @@ var Scenario = function (astTreeWalker, astScenario) { if (!mimeType) throw Error(Scenario.ATTACH_MISSING_MIME_TYPE_ARGUMENT); - astTreeWalker.attach(data.toString(), mimeType); + astTreeWalker.attach(data.toString('binary'), mimeType); - if (callback) { + if (callback) callback(); - } } else { - if (!mimeType) { + if (!mimeType) mimeType = Scenario.DEFAULT_TEXT_MIME_TYPE; - } - astTreeWalker.attach(data.toString(), mimeType); + astTreeWalker.attach(new Buffer(data.toString(), 'utf8').toString('binary'), mimeType); } } }; diff --git a/spec/cucumber/api/scenario_spec.js b/spec/cucumber/api/scenario_spec.js index 310a68f7e..8c7da3762 100644 --- a/spec/cucumber/api/scenario_spec.js +++ b/spec/cucumber/api/scenario_spec.js @@ -135,7 +135,7 @@ describe("Cucumber.Api.Scenario", function() { spyOnStub(astTreeWalker, "attach"); scenario.attach(stream, mimeType, callback); - }) + }); it("does not call back straight away", function() { expect(callback).not.toHaveBeenCalled(); @@ -164,6 +164,33 @@ describe("Cucumber.Api.Scenario", function() { expect(callback).toHaveBeenCalled(); }); }); + + describe("when the stream finishes providing data and the data contains non-ASCII characters", function() { + var data1, data2, text; + + beforeEach(function() { + data1 = []; + data2 = []; + + for (var i = 0; i < 256; i++) { + data1.push(i); + data2.push(i); + } + + dataListener(new Buffer(data1)); + dataListener(new Buffer(data2)); + text = String.fromCharCode.apply(null, [].concat(data1, data2)); + endListener(); + }); + + it("instructs the ast tree walker to create an attachment containing the contents of the stream", function() { + expect(astTreeWalker.attach).toHaveBeenCalledWith(text, mimeType); + }); + + it("calls back", function() { + expect(callback).toHaveBeenCalled(); + }); + }); }) }); } @@ -173,7 +200,7 @@ describe("Cucumber.Api.Scenario", function() { beforeEach(function() { buffer = new Buffer("data"); - }) + }); it("throws an exception when the mimeType argument is missing", function() { expect(function() { scenario.attach(buffer); }).toThrow(new Error("Cucumber.Api.Scenario.attach() expects a mimeType")); @@ -203,6 +230,47 @@ describe("Cucumber.Api.Scenario", function() { expect(callback).not.toHaveBeenCalled(); }); }); + + describe("when the buffer contains an array of bytes", function() { + var data, text, buffer; + + beforeEach(function() { + data = []; + + for (var i = 0; i < 256; i++) { + data.push(i); + } + + text = String.fromCharCode.apply(null, data); + buffer = new Buffer(data); + }); + + it("instructs the ast tree walker to create an attachment containing the contents of the buffer", function() { + scenario.attach(buffer, mimeType); + expect(astTreeWalker.attach).toHaveBeenCalledWith(text, mimeType); + }); + }); + + describe("when the buffer contains a UTF-8 encoded string", function() { + var data, text, buffer, utf8EncodedText; + + beforeEach(function() { + data = []; + + for (var i = 0; i < 512; i++) { + data.push(i); + } + + text = String.fromCharCode.apply(null, data); + buffer = new Buffer(text, 'utf8'); + utf8EncodedText = new Buffer(text, 'utf8').toString('binary'); + }); + + it("instructs the ast tree walker to create an attachment containing the contents of the buffer", function() { + scenario.attach(buffer, mimeType); + expect(astTreeWalker.attach).toHaveBeenCalledWith(utf8EncodedText, mimeType); + }); + }); }); describe("when the data is a string", function() { @@ -221,6 +289,31 @@ describe("Cucumber.Api.Scenario", function() { scenario.attach(data); expect(astTreeWalker.attach).toHaveBeenCalledWith(data, "text/plain"); }); + + describe("when the string is a UTF-8 encoded string", function() { + var data, text, utf8EncodedText; + + beforeEach(function() { + data = []; + + for (var i = 0; i < 512; i++) { + data.push(i); + } + + text = String.fromCharCode.apply(null, data); + utf8EncodedText = new Buffer(text, 'utf8').toString('binary'); + }); + + it("instructs the ast tree walker to create an attachment containing the string", function() { + scenario.attach(text, mimeType); + expect(astTreeWalker.attach).toHaveBeenCalledWith(utf8EncodedText, mimeType); + }); + + it("defaults to the plain text mime type when the mimeType argument is missing", function() { + scenario.attach(text); + expect(astTreeWalker.attach).toHaveBeenCalledWith(utf8EncodedText, "text/plain"); + }); + }); }); }); });