<commit_before>var React = require('react');
var d3 = require('d3');

var gaugeComponents = require('./gaugecomponents');
var getShadow = gaugeComponents.getShadow;
var getHand = gaugeComponents.getHand;

var size = 400;
var half = size / 2;
var strokeWidth = 25;

var propulsionPrefix = '^propulsion\.[A-Za-z0-9-]*\.';
var pathsCovered = [
  "navigation.speedOverGround",
  propulsionPrefix + "engineTemperature$",
  propulsionPrefix + 'oilTemperature',
  propulsionPrefix + 'oilPressure',
  propulsionPrefix + 'transmissionOilPressure',
  propulsionPrefix + 'rpm'
];

var config = {
  engineTemperature : {
    redLine: 90,
    max: 110
  },
  oilTemperature : {
    redLine: 200,
    max: 250
  },
  oilPressure : {
    redLine: 90,
    max: 110
  },
  transmissionOilPressure : {
    redLine: 240,
    max: 260
  },
  rpm : {
    redLine: 2500,
    max: 3000
  }
}

var componentClass = React.createClass({
  getInitialState: function() {
    var pathParts = this.props.path.split('.');
    var pathConfig = config[pathParts[pathParts.length -1]];
    return {
      value: 0,
      label: this.props.label,
      minValue: 0,
      maxValue: pathConfig ? pathConfig.max : 1,
      redLine: pathConfig ? pathConfig.redLine : 0.9
    };
  },

  renderTicks: function(scale) {
    var yOffset = 0;
    return scale.ticks().map(function(i) {
      return (
    <g key={"text-" + i} transform={'rotate(' + scale(i) + ' 200 0)'}>
      <text x={-half} y={yOffset + 10} textAnchor="middle" dominant-baseline="central" style={{"fontSize":"28px"}}
        transform={"rotate(" + -scale(i) + ")"}>{i}</text>
    </g>
)
    });
  },

  render: function() {
    var degreesScale = d3.scale.linear()
       .domain([this.state.minValue, this.state.maxValue])
       .range([10, 170]).clamp(true);

    var radianScale = d3.scale.linear()
       .domain([this.state.minValue, this.state.maxValue])
       .range([-80, 80]);

    var arcInset = 30;

    var arc = d3.svg.arc()
          .startAngle(deg2rad(-80))
          .endAngle(deg2rad(80))
          .innerRadius(half  - strokeWidth - arcInset)
          .outerRadius(half - arcInset)
          .cornerRadius(strokeWidth/4);

    var redArc = d3.svg.arc()
          .startAngle(deg2rad(radianScale(this.state.redLine)))
          .endAngle(deg2rad(radianScale(this.state.maxValue)))
          .innerRadius(half  - strokeWidth - arcInset)
          .outerRadius(half - arcInset)
          .cornerRadius(strokeWidth/4);

    var innerArc = d3.svg.arc()
          .startAngle(deg2rad(-80))
          .endAngle(deg2rad(80))
          .outerRadius(half  - strokeWidth - arcInset)
          .innerRadius(half / 20);

    var ticks = degreesScale.ticks([5]).slice(1,5);

    return (
      <svg height="100%" width="100%" viewBox="0 -20 400 240">
        <svg dangerouslySetInnerHTML={getShadow()} />
        <g transform={'translate(' + half + ',' + half + ' )'} stroke="black">

          {ticks.map(function(i){
            return (
              <path key={"tick-" + i}
                    d={"M -180 0 L -176 0"}
                    strokeWidth={2}
                    transform={'rotate(' + degreesScale(i) + ')'}
                    stroke="black"/>
            )
          })}

          <path d={arc()} stroke="black" stroke-width="5" fill="white" />

          <path d={redArc()} stroke="black" stroke-width="5" fill="red" />

          {getHand(200 - arcInset/2, degreesScale(this.state.value)-90)}

          <path d={innerArc()} stroke="none" stroke-width="5" fill="#efefef" opacity="0.8" />

          {this.renderTicks(degreesScale)}

          <text  y="-50" textAnchor="middle" fontSize="70" dominantBaseline="middle">
            <tspan x="0">{BaseWidget.prototype.displayValue(this.state.value)}</tspan>
            <tspan x="0" dy="30" fontSize="30">-</tspan>
            <tspan x="0" dy="30" fontSize="30">{this.props.label}</tspan>
          </text>

        </g>
      </svg>
    )
  },

  componentDidMount: function() {
    if (this.props.value) {
      this.unsubscribe = this.props.value.onValue(function(value) {
        var nextState = {
          value: value
        };
        this.setState(nextState);
      }.bind(this));
    }
  },

  componentWillUnmount: function() {
    if(this.unsubscribe) {
      this.unsubscribe();
    }
  }
});

var BaseWidget = require('./basewidget');
require('util').inherits(Widget, BaseWidget);

function Widget(id, options, streamBundle, instrumentPanel) {
  BaseWidget.call(this, id, options, streamBundle, instrumentPanel);
  this.options = options;
  var pathParts = options.path.split('.');
  this.widget = React.createElement(componentClass,{
    key: id,
    value: streamBundle.getStream(options.path),
    label: options.path,
    path: options.path
  });
}

Widget.prototype.getReactElement = function() {
  return this.widget;
}

Widget.prototype.getType = function() {
  return "analog";
}

Widget.prototype.getHandledPaths = function() {
  return [this.options.path];
}

Widget.prototype.getOptions = function() {
  return this.options;
}

function deg2rad(deg) {
  return deg / 180 * Math.PI;
}

module.exports = {
  constructor: Widget,
  type: "analog",
  paths: pathsCovered
}
<commit_msg>strokeWidth<commit_after>var React = require('react');
var d3 = require('d3');

var gaugeComponents = require('./gaugecomponents');
var getShadow = gaugeComponents.getShadow;
var getHand = gaugeComponents.getHand;

var size = 400;
var half = size / 2;
var strokeWidth = 25;

var propulsionPrefix = '^propulsion\.[A-Za-z0-9-]*\.';
var pathsCovered = [
  "navigation.speedOverGround",
  propulsionPrefix + "engineTemperature$",
  propulsionPrefix + 'oilTemperature',
  propulsionPrefix + 'oilPressure',
  propulsionPrefix + 'transmissionOilPressure',
  propulsionPrefix + 'rpm'
];

var config = {
  engineTemperature : {
    redLine: 90,
    max: 110
  },
  oilTemperature : {
    redLine: 200,
    max: 250
  },
  oilPressure : {
    redLine: 90,
    max: 110
  },
  transmissionOilPressure : {
    redLine: 240,
    max: 260
  },
  rpm : {
    redLine: 2500,
    max: 3000
  }
}

var componentClass = React.createClass({
  getInitialState: function() {
    var pathParts = this.props.path.split('.');
    var pathConfig = config[pathParts[pathParts.length -1]];
    return {
      value: 0,
      label: this.props.label,
      minValue: 0,
      maxValue: pathConfig ? pathConfig.max : 1,
      redLine: pathConfig ? pathConfig.redLine : 0.9
    };
  },

  renderTicks: function(scale) {
    var yOffset = 0;
    return scale.ticks().map(function(i) {
      return (
    <g key={"text-" + i} transform={'rotate(' + scale(i) + ' 200 0)'}>
      <text x={-half} y={yOffset + 10} textAnchor="middle" dominant-baseline="central" style={{"fontSize":"28px"}}
        transform={"rotate(" + -scale(i) + ")"}>{i}</text>
    </g>
)
    });
  },

  render: function() {
    var degreesScale = d3.scale.linear()
       .domain([this.state.minValue, this.state.maxValue])
       .range([10, 170]).clamp(true);

    var radianScale = d3.scale.linear()
       .domain([this.state.minValue, this.state.maxValue])
       .range([-80, 80]);

    var arcInset = 30;

    var arc = d3.svg.arc()
          .startAngle(deg2rad(-80))
          .endAngle(deg2rad(80))
          .innerRadius(half  - strokeWidth - arcInset)
          .outerRadius(half - arcInset)
          .cornerRadius(strokeWidth/4);

    var redArc = d3.svg.arc()
          .startAngle(deg2rad(radianScale(this.state.redLine)))
          .endAngle(deg2rad(radianScale(this.state.maxValue)))
          .innerRadius(half  - strokeWidth - arcInset)
          .outerRadius(half - arcInset)
          .cornerRadius(strokeWidth/4);

    var innerArc = d3.svg.arc()
          .startAngle(deg2rad(-80))
          .endAngle(deg2rad(80))
          .outerRadius(half  - strokeWidth - arcInset)
          .innerRadius(half / 20);

    var ticks = degreesScale.ticks([5]).slice(1,5);

    return (
      <svg height="100%" width="100%" viewBox="0 -20 400 240">
        <svg dangerouslySetInnerHTML={getShadow()} />
        <g transform={'translate(' + half + ',' + half + ' )'} stroke="black">

          {ticks.map(function(i){
            return (
              <path key={"tick-" + i}
                    d={"M -180 0 L -176 0"}
                    strokeWidth={2}
                    transform={'rotate(' + degreesScale(i) + ')'}
                    stroke="black"/>
            )
          })}

          <path d={arc()} stroke="black" strokeWidth="5" fill="white" />

          <path d={redArc()} stroke="black" strokeWidth="5" fill="red" />

          {getHand(200 - arcInset/2, degreesScale(this.state.value)-90)}

          <path d={innerArc()} stroke="none" strokeWidth="5" fill="#efefef" opacity="0.8" />

          {this.renderTicks(degreesScale)}

          <text  y="-50" textAnchor="middle" fontSize="70" dominantBaseline="middle">
            <tspan x="0">{BaseWidget.prototype.displayValue(this.state.value)}</tspan>
            <tspan x="0" dy="30" fontSize="30">-</tspan>
            <tspan x="0" dy="30" fontSize="30">{this.props.label}</tspan>
          </text>

        </g>
      </svg>
    )
  },

  componentDidMount: function() {
    if (this.props.value) {
      this.unsubscribe = this.props.value.onValue(function(value) {
        var nextState = {
          value: value
        };
        this.setState(nextState);
      }.bind(this));
    }
  },

  componentWillUnmount: function() {
    if(this.unsubscribe) {
      this.unsubscribe();
    }
  }
});

var BaseWidget = require('./basewidget');
require('util').inherits(Widget, BaseWidget);

function Widget(id, options, streamBundle, instrumentPanel) {
  BaseWidget.call(this, id, options, streamBundle, instrumentPanel);
  this.options = options;
  var pathParts = options.path.split('.');
  this.widget = React.createElement(componentClass,{
    key: id,
    value: streamBundle.getStream(options.path),
    label: options.path,
    path: options.path
  });
}

Widget.prototype.getReactElement = function() {
  return this.widget;
}

Widget.prototype.getType = function() {
  return "analog";
}

Widget.prototype.getHandledPaths = function() {
  return [this.options.path];
}

Widget.prototype.getOptions = function() {
  return this.options;
}

function deg2rad(deg) {
  return deg / 180 * Math.PI;
}

module.exports = {
  constructor: Widget,
  type: "analog",
  paths: pathsCovered
}
<|endoftext|>


<commit_before>/*global setImmediate:true*/

if (typeof setImmediate === 'undefined') {
    setImmediate = process.nextTick;
}

var http = require('http'),
    stream = require('stream'),
    isStream = require('is-stream'),
    _ = require('underscore'),
    FormData = require('form-data'),
    qs = require('qs'),
    messy = require('messy'),
    metadataPropertyNames = ['strictAsync', 'errorPassedToNext', 'isDestroyed', 'nextCalled', 'locals', 'url', 'requestDestroyed'],
    responsePropertyNames = messy.HttpResponse.propertyNames.concat(metadataPropertyNames);

function hasKeys(x) {
    return Object.keys(x).length > 0;
}

function validateResponseProperties(x) {
    return _.intersection(Object.keys(x), responsePropertyNames).length > 0;
}

module.exports = {
    name: 'unexpected-express',
    version: require('../package.json').version,
    installInto: function (expect) {
        expect = expect.child();

        var topLevelExpect = expect;

        expect.use(require('unexpected-messy'));

        expect.addType({
            name: 'IncomingMessage',
            base: 'object',
            identify: function (obj) {
                return obj && obj.constructor && obj.constructor.name === 'IncomingMessage';
            },
            inspect: function (obj, depth, output) {
                output.text(obj.constructor.name, 'jsFunctionName');
            }
        });

        expect.exportAssertion([
            '<function> to yield exchange satisfying <any>', // Please prefer this one because it does use 'to satisfy' semantics
            '<function> to yield exchange <any>'
        ], function (expect, subject, value) {
            if (!subject.handle || !subject.set) {
                // This check is from the lib/application file in express @ 4.10.2.
                // If we get inside here, we have something that is not an express app
                // https://github.com/strongloop/express/blob/661435256384165bb656cb7b6046b4138ca24c9e/lib/application.js#L186
                subject = require('express')().use(subject);
                this.subjectOutput = function () {
                    this.text('express middleware');
                };
            } else {
                this.subjectOutput = function () {
                    this.text('express app');
                };
            }

            var missingProperties = Object.keys(value).filter(function (key) {
                return key !== 'request' && key !== 'response';
            });
            if (missingProperties.length > 0) {
                throw new Error('Property "' + missingProperties[0] + '" does not exist');
            }

            var context = {},
                nextCalls = [];

            value = _.extend({}, value);
            var requestProperties = typeof value.request === 'string' ? {url: value.request} : _.extend({}, value.request),
                requestBody = requestProperties.body,
                requestForm = requestProperties.form,
                httpRequest = new messy.HttpRequest({
                    method: requestProperties.method,
                    url: requestProperties.url || '/',
                    protocolName: 'HTTP',
                    protocolVersion: requestProperties.httpVersion || '1.1',
                    headers: requestProperties.headers,
                    unchunkedBody: requestProperties.unchunkedBody,
                    rawBody: requestProperties.rawBody
                });

            function updateHttpRequestBody(requestBody) {
                if (Buffer.isBuffer(requestBody)) {
                    httpRequest.unchunkedBody = requestBody;
                } else {
                    // string or non-Buffer object (implies JSON)
                    httpRequest.body = requestBody;
                }
            }

            if (requestForm) {
                if (typeof requestForm !== 'string') {
                    requestForm = qs.stringify(requestForm);
                }
                requestBody = requestForm;
                if (!httpRequest.headers.has('Content-Type')) {
                    httpRequest.headers.set('Content-Type', 'application/x-www-form-urlencoded');
                }
            }

            if (typeof requestBody !== 'undefined') {
                updateHttpRequestBody(requestBody);
            } else if ('unchunkedBody' in requestProperties || 'rawBody' in requestProperties) {
                requestBody = httpRequest.body;
            }

            delete value.request;
            delete requestProperties.method;
            delete requestProperties.url;
            delete requestProperties.httpVersion;
            delete requestProperties.headers;
            delete requestProperties.body;
            delete requestProperties.unchunkedBody;
            delete requestProperties.rawBody;
            httpRequest.method = httpRequest.method || 'GET';
            if (httpRequest.encrypted && typeof requestProperties.https === 'undefined') {
                // Warn if conflicting?
                requestProperties.https = true;
            }
            if (requestProperties.formData) {
                if (requestBody) {
                    throw new Error('unexpected-express: The "body" and "formData" options are not supported together');
                }
                requestBody = new FormData();
                Object.keys(requestProperties.formData).forEach(function (name) {
                    var value = requestProperties.formData[name],
                        options = {};

                    if (isStream.readable(value) && value.path) {
                        options.filename = value.path;
                    } else if (typeof value === 'object' && !Buffer.isBuffer(value)) {
                        options = _.extend({}, value);
                        value = options.value;
                        delete options.value;
                        if (options.fileName) {
                            options.filename = options.fileName;
                            delete options.fileName;
                        }
                    }
                    requestBody.append(name, value, options);
                });

                delete requestProperties.formData;
            }

            if (typeof requestProperties.query !== 'undefined') {
                if (typeof requestProperties.query === 'object' && requestProperties.query) {
                    var stringifiedQueryString = qs.stringify(requestProperties.query);
                    if (stringifiedQueryString) {
                        httpRequest.url += (httpRequest.url.indexOf('?') === -1 ? '?' : '&') + stringifiedQueryString;
                    }
                } else {
                    httpRequest.url += (httpRequest.url.indexOf('?') === -1 ? '?' : '&') + String(requestProperties.query);
                }
                delete requestProperties.query;
            }

            var responseProperties = value.response;
            delete value.response;
            var expectedResponseProperties;

            if (typeof responseProperties === 'number') {
                expectedResponseProperties = {statusCode: responseProperties};
            } else if (typeof responseProperties === 'string' || Buffer.isBuffer(responseProperties)) {
                expectedResponseProperties = {body: responseProperties};
            } else if (Array.isArray(responseProperties)) {
                throw new Error('unexpected-express: Response object must be a number, string, buffer or object.');
            } else {
                if (responseProperties && hasKeys(responseProperties) && !validateResponseProperties(responseProperties)) {
                    throw new Error('unexpected-express: Response object specification incomplete.');
                }

                expectedResponseProperties = _.extend({}, responseProperties);
            }

            var expectedMetadata = _.extend(
                {},
                _.pick(expectedResponseProperties, metadataPropertyNames),
                _.pick(value, metadataPropertyNames)
            );
            expectedResponseProperties = _.omit(expectedResponseProperties, metadataPropertyNames);

            var missingResponseProperties = Object.keys(expectedResponseProperties).filter(function (key) {
                return responsePropertyNames.indexOf(key) === -1;
            });
            if (missingResponseProperties.length > 0) {
                throw new Error('Property "' + missingResponseProperties[0] + '" does not exist on the response object.');
            }

            var req = new http.IncomingMessage({
                destroy: function () {
                    requestDestroyed = true;
                }
            });

            if (typeof requestBody !== 'undefined') {
                httpRequest.headers.set('Transfer-Encoding', 'chunked');
                if (requestBody.pipe) {
                    if (requestBody.constructor && requestBody.constructor.name === 'FormData') {
                        if (!httpRequest.headers.has('Content-Type')) {
                            httpRequest.headers.set('Content-Type', 'multipart/form-data; boundary=' + requestBody.getBoundary());
                            // form-data pauses its streams by default for some reason:
                            setImmediate(function () {
                                requestBody.resume();
                            });
                        }
                    }
                    var requestBodyChunks = [];
                    requestBody.on('data', function (chunk) {
                        if (!Buffer.isBuffer(chunk)) {
                            chunk = Buffer.from(chunk, 'utf-8');
                        }
                        requestBodyChunks.push(chunk);
                        req.push(chunk);
                    }).on('end', function () {
                        updateHttpRequestBody(Buffer.concat(requestBodyChunks));
                        req.push(null);
                    }).on('error', function (err) {
                        req.emit('error', err);
                    });
                } else {
                    if (typeof requestBody === 'object' && !Buffer.isBuffer(requestBody)) {
                        if (!httpRequest.headers.has('Content-Type')) {
                            httpRequest.headers.set('Content-Type', 'application/json');
                        }
                    }

                    if (!httpRequest.headers.has('Content-Length') && !httpRequest.headers.has('Transfer-Encoding')) {
                        httpRequest.headers.set('Content-Length', String(requestBody.length));
                    }
                    setImmediate(function () {
                        // To work around nodejs v0.10.x issue with old-style streams, see also https://github.com/stream-utils/raw-body/pull/34
                        req.push(httpRequest.unchunkedBody);
                        req.push(null);
                    });
                }
            } else {
                req.push(null);
            }

            // Make req.connection.setTimeout a no-op so that req.setTimeout doesn't break
            // in this mocked state:
            req.connection.setTimeout = function () {};

            req.httpVersion = httpRequest.protocolVersion;
            var matchProtocolVersion = String(httpRequest.protocolVersion).match(/^(\d+)(?:\.(\d+))$/);
            if (matchProtocolVersion) {
                req.httpVersionMajor = parseInt(matchProtocolVersion[1], 10);
                req.httpVersionMinor = matchProtocolVersion[2] ? parseInt(matchProtocolVersion[2], 10) : 0;
            }
            req.connection.encrypted = !!requestProperties.https;
            delete requestProperties.https;
            req.connection.remoteAddress = requestProperties.remoteAddress || requestProperties.ip || '127.0.0.1';
            delete requestProperties.ip;
            delete requestProperties.remoteAddress;
            req.headers = {};
            httpRequest.headers.getNames().forEach(function (headerName) {
                var headerNameLowerCase = headerName.toLowerCase();
                if (headerNameLowerCase === 'set-cookie') {
                    req.headers[headerNameLowerCase] = [].concat(httpRequest.headers.getAll(headerName));
                } else {
                    req.headers[headerNameLowerCase] = httpRequest.headers.getAll(headerName).join(', ');
                }
            });
            req.method = httpRequest.method;
            req.url = httpRequest.requestLine.url;
            _.extend(req, requestProperties);

            var res = new http.ServerResponse(req);
            _.extend(res, requestProperties.res); // Allows for specifying eg. res.locals
            delete requestProperties.res;
            res.locals = res.locals || {};

            var rawResponseChunks = [];
            res.assignSocket(new stream.Writable());
            res.connection._write = function (chunk, encoding, cb) {
                rawResponseChunks.push(chunk);
                cb();
            };
            var isAsync = false,
                isDestroyed = false,
                requestDestroyed = false,
                done = false,
                errorPassedToNext;

            res.connection.destroy = function () {
                isDestroyed = true;
            };

            setImmediate(function () {
                isAsync = true;
            });

            return expect.promise(function (resolve, reject) {
                ['write', 'end', 'destroy'].forEach(function (methodName) {
                    var orig = res[methodName];
                    res[methodName] = function (chunk, encoding) {
                        var returnValue = orig.apply(this, arguments);
                        isDestroyed = isDestroyed || methodName === 'destroy';
                        if (methodName === 'end' || methodName === 'destroy') {
                            resolve();
                        }
                        // Don't attempt to implement backpressure, since we're buffering the entire response anyway.
                        if (methodName !== 'write') {
                            return returnValue;
                        }
                    };
                });
                subject(req, res, function (err, _req, _res, _next) {
                    nextCalls.push(arguments);
                    if (nextCalls.length > 1) {
                        if (done) {
                            if (err) {
                                throw err;
                            } else {
                                throw new Error('next called more than once');
                            }
                        } else {
                            // Will be reported as a failure later
                            return;
                        }
                    }
                    errorPassedToNext = err;
                    if (typeof err === 'number') {
                        var statusCode = err;
                        err = new Error('' + statusCode);
                        err.statusCode = statusCode;
                    }
                    res.statusCode = err && (err.statusCode || err.status) || 404;
                    resolve();
                });
            }).then(function () {
                if (res.connection._writableState.corked > 0) {
                    // Wait for the connection to become uncorked before proceeding
                    var originalUncork = res.connection.uncork;
                    return expect.promise(function (resolve, reject) {
                        res.connection.uncork = function () {
                            var returnValue = originalUncork.apply(this, arguments);
                            if (res.connection._writableState.corked === 0) {
                                resolve();
                            }
                            return returnValue;
                        };
                    });
                }
            }).then(function () {
                _.extend(context, {
                    req: req,
                    res: res,
                    httpRequest: httpRequest,
                    metadata: {
                        strictAsync: isAsync,
                        errorPassedToNext: false,
                        isDestroyed: isDestroyed,
                        requestDestroyed: requestDestroyed,
                        nextCalled: nextCalls.length > 0,
                        locals: res.locals,
                        url: req.url
                    }
                });

                if (errorPassedToNext && errorPassedToNext.statusCode && !res.headersSent) {
                    res.writeHead(errorPassedToNext.statusCode);
                }

                if (!res.headersSent) {
                    // Make sure that the already set headers get flushed:
                    res.writeHead(404);
                }

                var httpResponse = context.httpResponse = new messy.HttpResponse(
                    rawResponseChunks.length > 0 ? Buffer.concat(rawResponseChunks) : res._header
                );
                if (typeof httpResponse.rawBody === 'undefined') {
                    httpResponse.rawBody = Buffer.from([]);
                }
                httpResponse.statusCode = httpResponse.statusCode || res.statusCode;

                if (errorPassedToNext) {
                    context.metadata.errorPassedToNext = errorPassedToNext;
                    if (typeof expectedMetadata.errorPassedToNext !== 'undefined') {
                        if (expectedMetadata.errorPassedToNext === true) {
                            context.metadata.errorPassedToNext = true;
                        } else if (typeof expectedMetadata.errorPassedToNext === 'string') {
                            context.metadata.errorPassedToNext = errorPassedToNext.message;
                        } else {
                            context.metadata.errorPassedToNext = errorPassedToNext;
                        }
                    } else if (typeof errorPassedToNext.statusCode === 'number') {
                        // FIXME
                        if (!httpResponse.headers.get('Content-Type')) {
                            httpResponse.headers.set('Content-Type', 'text/plain');
                            httpResponse.body = errorPassedToNext.stack;
                        }
                    } else {
                        throw errorPassedToNext;
                    }
                }

                context.httpExchange = new messy.HttpExchange({
                    request: context.httpRequest,
                    response: context.httpResponse
                });

                var promiseByKey = {
                    httpExchange: expect.promise(function () {
                        return expect(context.httpExchange, 'to satisfy', {response: expectedResponseProperties});
                    }),
                    metadata: {}
                };
                Object.keys(expectedMetadata).forEach(function (key) {
                    promiseByKey.metadata[key] = expect.promise(function () {
                        return topLevelExpect(context.metadata[key], 'to satisfy', expectedMetadata[key]);
                    });
                });
                return expect.promise.settle(promiseByKey).then(function (promises) {
                    if (promises.some(function (promise) { return promise.isRejected(); })) {
                        expect.fail({
                            diff: function (output) {
                                if (promiseByKey.httpExchange.isRejected()) {
                                    output.append(promiseByKey.httpExchange.reason().getDiff(output));
                                } else {
                                    output.appendInspected(context.httpExchange);
                                }
                                Object.keys(promiseByKey.metadata).forEach(function (key) {
                                    if (promiseByKey.metadata[key].isRejected()) {
                                        output.nl().annotationBlock(function () {
                                            this.text(key).text(':').sp().append(promiseByKey.metadata[key].reason().getErrorMessage(output));
                                        });
                                    }
                                });
                                return output;
                            }
                        });
                    }
                });
            }).then(function () {
                if (nextCalls.length > 1) {
                    throw new Error('next called more than once');
                }
                done = true; // Tell the next function that subsequent calls should cause an exception to be thrown
                return context;
            });
        });
    }
};

module.exports.messy = messy;
<commit_msg>Override subjectOutput on expect, not this (no longer works in 11.0.0)<commit_after>/*global setImmediate:true*/

if (typeof setImmediate === 'undefined') {
    setImmediate = process.nextTick;
}

var http = require('http'),
    stream = require('stream'),
    isStream = require('is-stream'),
    _ = require('underscore'),
    FormData = require('form-data'),
    qs = require('qs'),
    messy = require('messy'),
    metadataPropertyNames = ['strictAsync', 'errorPassedToNext', 'isDestroyed', 'nextCalled', 'locals', 'url', 'requestDestroyed'],
    responsePropertyNames = messy.HttpResponse.propertyNames.concat(metadataPropertyNames);

function hasKeys(x) {
    return Object.keys(x).length > 0;
}

function validateResponseProperties(x) {
    return _.intersection(Object.keys(x), responsePropertyNames).length > 0;
}

module.exports = {
    name: 'unexpected-express',
    version: require('../package.json').version,
    installInto: function (expect) {
        expect = expect.child();

        var topLevelExpect = expect;

        expect.use(require('unexpected-messy'));

        expect.addType({
            name: 'IncomingMessage',
            base: 'object',
            identify: function (obj) {
                return obj && obj.constructor && obj.constructor.name === 'IncomingMessage';
            },
            inspect: function (obj, depth, output) {
                output.text(obj.constructor.name, 'jsFunctionName');
            }
        });

        expect.exportAssertion([
            '<function> to yield exchange satisfying <any>', // Please prefer this one because it does use 'to satisfy' semantics
            '<function> to yield exchange <any>'
        ], function (expect, subject, value) {
            if (!subject.handle || !subject.set) {
                // This check is from the lib/application file in express @ 4.10.2.
                // If we get inside here, we have something that is not an express app
                // https://github.com/strongloop/express/blob/661435256384165bb656cb7b6046b4138ca24c9e/lib/application.js#L186
                subject = require('express')().use(subject);
                expect.subjectOutput = function () {
                    this.text('express middleware');
                };
            } else {
                expect.subjectOutput = function () {
                    this.text('express app');
                };
            }

            var missingProperties = Object.keys(value).filter(function (key) {
                return key !== 'request' && key !== 'response';
            });
            if (missingProperties.length > 0) {
                throw new Error('Property "' + missingProperties[0] + '" does not exist');
            }

            var context = {},
                nextCalls = [];

            value = _.extend({}, value);
            var requestProperties = typeof value.request === 'string' ? {url: value.request} : _.extend({}, value.request),
                requestBody = requestProperties.body,
                requestForm = requestProperties.form,
                httpRequest = new messy.HttpRequest({
                    method: requestProperties.method,
                    url: requestProperties.url || '/',
                    protocolName: 'HTTP',
                    protocolVersion: requestProperties.httpVersion || '1.1',
                    headers: requestProperties.headers,
                    unchunkedBody: requestProperties.unchunkedBody,
                    rawBody: requestProperties.rawBody
                });

            function updateHttpRequestBody(requestBody) {
                if (Buffer.isBuffer(requestBody)) {
                    httpRequest.unchunkedBody = requestBody;
                } else {
                    // string or non-Buffer object (implies JSON)
                    httpRequest.body = requestBody;
                }
            }

            if (requestForm) {
                if (typeof requestForm !== 'string') {
                    requestForm = qs.stringify(requestForm);
                }
                requestBody = requestForm;
                if (!httpRequest.headers.has('Content-Type')) {
                    httpRequest.headers.set('Content-Type', 'application/x-www-form-urlencoded');
                }
            }

            if (typeof requestBody !== 'undefined') {
                updateHttpRequestBody(requestBody);
            } else if ('unchunkedBody' in requestProperties || 'rawBody' in requestProperties) {
                requestBody = httpRequest.body;
            }

            delete value.request;
            delete requestProperties.method;
            delete requestProperties.url;
            delete requestProperties.httpVersion;
            delete requestProperties.headers;
            delete requestProperties.body;
            delete requestProperties.unchunkedBody;
            delete requestProperties.rawBody;
            httpRequest.method = httpRequest.method || 'GET';
            if (httpRequest.encrypted && typeof requestProperties.https === 'undefined') {
                // Warn if conflicting?
                requestProperties.https = true;
            }
            if (requestProperties.formData) {
                if (requestBody) {
                    throw new Error('unexpected-express: The "body" and "formData" options are not supported together');
                }
                requestBody = new FormData();
                Object.keys(requestProperties.formData).forEach(function (name) {
                    var value = requestProperties.formData[name],
                        options = {};

                    if (isStream.readable(value) && value.path) {
                        options.filename = value.path;
                    } else if (typeof value === 'object' && !Buffer.isBuffer(value)) {
                        options = _.extend({}, value);
                        value = options.value;
                        delete options.value;
                        if (options.fileName) {
                            options.filename = options.fileName;
                            delete options.fileName;
                        }
                    }
                    requestBody.append(name, value, options);
                });

                delete requestProperties.formData;
            }

            if (typeof requestProperties.query !== 'undefined') {
                if (typeof requestProperties.query === 'object' && requestProperties.query) {
                    var stringifiedQueryString = qs.stringify(requestProperties.query);
                    if (stringifiedQueryString) {
                        httpRequest.url += (httpRequest.url.indexOf('?') === -1 ? '?' : '&') + stringifiedQueryString;
                    }
                } else {
                    httpRequest.url += (httpRequest.url.indexOf('?') === -1 ? '?' : '&') + String(requestProperties.query);
                }
                delete requestProperties.query;
            }

            var responseProperties = value.response;
            delete value.response;
            var expectedResponseProperties;

            if (typeof responseProperties === 'number') {
                expectedResponseProperties = {statusCode: responseProperties};
            } else if (typeof responseProperties === 'string' || Buffer.isBuffer(responseProperties)) {
                expectedResponseProperties = {body: responseProperties};
            } else if (Array.isArray(responseProperties)) {
                throw new Error('unexpected-express: Response object must be a number, string, buffer or object.');
            } else {
                if (responseProperties && hasKeys(responseProperties) && !validateResponseProperties(responseProperties)) {
                    throw new Error('unexpected-express: Response object specification incomplete.');
                }

                expectedResponseProperties = _.extend({}, responseProperties);
            }

            var expectedMetadata = _.extend(
                {},
                _.pick(expectedResponseProperties, metadataPropertyNames),
                _.pick(value, metadataPropertyNames)
            );
            expectedResponseProperties = _.omit(expectedResponseProperties, metadataPropertyNames);

            var missingResponseProperties = Object.keys(expectedResponseProperties).filter(function (key) {
                return responsePropertyNames.indexOf(key) === -1;
            });
            if (missingResponseProperties.length > 0) {
                throw new Error('Property "' + missingResponseProperties[0] + '" does not exist on the response object.');
            }

            var req = new http.IncomingMessage({
                destroy: function () {
                    requestDestroyed = true;
                }
            });

            if (typeof requestBody !== 'undefined') {
                httpRequest.headers.set('Transfer-Encoding', 'chunked');
                if (requestBody.pipe) {
                    if (requestBody.constructor && requestBody.constructor.name === 'FormData') {
                        if (!httpRequest.headers.has('Content-Type')) {
                            httpRequest.headers.set('Content-Type', 'multipart/form-data; boundary=' + requestBody.getBoundary());
                            // form-data pauses its streams by default for some reason:
                            setImmediate(function () {
                                requestBody.resume();
                            });
                        }
                    }
                    var requestBodyChunks = [];
                    requestBody.on('data', function (chunk) {
                        if (!Buffer.isBuffer(chunk)) {
                            chunk = Buffer.from(chunk, 'utf-8');
                        }
                        requestBodyChunks.push(chunk);
                        req.push(chunk);
                    }).on('end', function () {
                        updateHttpRequestBody(Buffer.concat(requestBodyChunks));
                        req.push(null);
                    }).on('error', function (err) {
                        req.emit('error', err);
                    });
                } else {
                    if (typeof requestBody === 'object' && !Buffer.isBuffer(requestBody)) {
                        if (!httpRequest.headers.has('Content-Type')) {
                            httpRequest.headers.set('Content-Type', 'application/json');
                        }
                    }

                    if (!httpRequest.headers.has('Content-Length') && !httpRequest.headers.has('Transfer-Encoding')) {
                        httpRequest.headers.set('Content-Length', String(requestBody.length));
                    }
                    setImmediate(function () {
                        // To work around nodejs v0.10.x issue with old-style streams, see also https://github.com/stream-utils/raw-body/pull/34
                        req.push(httpRequest.unchunkedBody);
                        req.push(null);
                    });
                }
            } else {
                req.push(null);
            }

            // Make req.connection.setTimeout a no-op so that req.setTimeout doesn't break
            // in this mocked state:
            req.connection.setTimeout = function () {};

            req.httpVersion = httpRequest.protocolVersion;
            var matchProtocolVersion = String(httpRequest.protocolVersion).match(/^(\d+)(?:\.(\d+))$/);
            if (matchProtocolVersion) {
                req.httpVersionMajor = parseInt(matchProtocolVersion[1], 10);
                req.httpVersionMinor = matchProtocolVersion[2] ? parseInt(matchProtocolVersion[2], 10) : 0;
            }
            req.connection.encrypted = !!requestProperties.https;
            delete requestProperties.https;
            req.connection.remoteAddress = requestProperties.remoteAddress || requestProperties.ip || '127.0.0.1';
            delete requestProperties.ip;
            delete requestProperties.remoteAddress;
            req.headers = {};
            httpRequest.headers.getNames().forEach(function (headerName) {
                var headerNameLowerCase = headerName.toLowerCase();
                if (headerNameLowerCase === 'set-cookie') {
                    req.headers[headerNameLowerCase] = [].concat(httpRequest.headers.getAll(headerName));
                } else {
                    req.headers[headerNameLowerCase] = httpRequest.headers.getAll(headerName).join(', ');
                }
            });
            req.method = httpRequest.method;
            req.url = httpRequest.requestLine.url;
            _.extend(req, requestProperties);

            var res = new http.ServerResponse(req);
            _.extend(res, requestProperties.res); // Allows for specifying eg. res.locals
            delete requestProperties.res;
            res.locals = res.locals || {};

            var rawResponseChunks = [];
            res.assignSocket(new stream.Writable());
            res.connection._write = function (chunk, encoding, cb) {
                rawResponseChunks.push(chunk);
                cb();
            };
            var isAsync = false,
                isDestroyed = false,
                requestDestroyed = false,
                done = false,
                errorPassedToNext;

            res.connection.destroy = function () {
                isDestroyed = true;
            };

            setImmediate(function () {
                isAsync = true;
            });

            return expect.promise(function (resolve, reject) {
                ['write', 'end', 'destroy'].forEach(function (methodName) {
                    var orig = res[methodName];
                    res[methodName] = function (chunk, encoding) {
                        var returnValue = orig.apply(this, arguments);
                        isDestroyed = isDestroyed || methodName === 'destroy';
                        if (methodName === 'end' || methodName === 'destroy') {
                            resolve();
                        }
                        // Don't attempt to implement backpressure, since we're buffering the entire response anyway.
                        if (methodName !== 'write') {
                            return returnValue;
                        }
                    };
                });
                subject(req, res, function (err, _req, _res, _next) {
                    nextCalls.push(arguments);
                    if (nextCalls.length > 1) {
                        if (done) {
                            if (err) {
                                throw err;
                            } else {
                                throw new Error('next called more than once');
                            }
                        } else {
                            // Will be reported as a failure later
                            return;
                        }
                    }
                    errorPassedToNext = err;
                    if (typeof err === 'number') {
                        var statusCode = err;
                        err = new Error('' + statusCode);
                        err.statusCode = statusCode;
                    }
                    res.statusCode = err && (err.statusCode || err.status) || 404;
                    resolve();
                });
            }).then(function () {
                if (res.connection._writableState.corked > 0) {
                    // Wait for the connection to become uncorked before proceeding
                    var originalUncork = res.connection.uncork;
                    return expect.promise(function (resolve, reject) {
                        res.connection.uncork = function () {
                            var returnValue = originalUncork.apply(this, arguments);
                            if (res.connection._writableState.corked === 0) {
                                resolve();
                            }
                            return returnValue;
                        };
                    });
                }
            }).then(function () {
                _.extend(context, {
                    req: req,
                    res: res,
                    httpRequest: httpRequest,
                    metadata: {
                        strictAsync: isAsync,
                        errorPassedToNext: false,
                        isDestroyed: isDestroyed,
                        requestDestroyed: requestDestroyed,
                        nextCalled: nextCalls.length > 0,
                        locals: res.locals,
                        url: req.url
                    }
                });

                if (errorPassedToNext && errorPassedToNext.statusCode && !res.headersSent) {
                    res.writeHead(errorPassedToNext.statusCode);
                }

                if (!res.headersSent) {
                    // Make sure that the already set headers get flushed:
                    res.writeHead(404);
                }

                var httpResponse = context.httpResponse = new messy.HttpResponse(
                    rawResponseChunks.length > 0 ? Buffer.concat(rawResponseChunks) : res._header
                );
                if (typeof httpResponse.rawBody === 'undefined') {
                    httpResponse.rawBody = Buffer.from([]);
                }
                httpResponse.statusCode = httpResponse.statusCode || res.statusCode;

                if (errorPassedToNext) {
                    context.metadata.errorPassedToNext = errorPassedToNext;
                    if (typeof expectedMetadata.errorPassedToNext !== 'undefined') {
                        if (expectedMetadata.errorPassedToNext === true) {
                            context.metadata.errorPassedToNext = true;
                        } else if (typeof expectedMetadata.errorPassedToNext === 'string') {
                            context.metadata.errorPassedToNext = errorPassedToNext.message;
                        } else {
                            context.metadata.errorPassedToNext = errorPassedToNext;
                        }
                    } else if (typeof errorPassedToNext.statusCode === 'number') {
                        // FIXME
                        if (!httpResponse.headers.get('Content-Type')) {
                            httpResponse.headers.set('Content-Type', 'text/plain');
                            httpResponse.body = errorPassedToNext.stack;
                        }
                    } else {
                        throw errorPassedToNext;
                    }
                }

                context.httpExchange = new messy.HttpExchange({
                    request: context.httpRequest,
                    response: context.httpResponse
                });

                var promiseByKey = {
                    httpExchange: expect.promise(function () {
                        return expect(context.httpExchange, 'to satisfy', {response: expectedResponseProperties});
                    }),
                    metadata: {}
                };
                Object.keys(expectedMetadata).forEach(function (key) {
                    promiseByKey.metadata[key] = expect.promise(function () {
                        return topLevelExpect(context.metadata[key], 'to satisfy', expectedMetadata[key]);
                    });
                });
                return expect.promise.settle(promiseByKey).then(function (promises) {
                    if (promises.some(function (promise) { return promise.isRejected(); })) {
                        expect.fail({
                            diff: function (output) {
                                if (promiseByKey.httpExchange.isRejected()) {
                                    output.append(promiseByKey.httpExchange.reason().getDiff(output));
                                } else {
                                    output.appendInspected(context.httpExchange);
                                }
                                Object.keys(promiseByKey.metadata).forEach(function (key) {
                                    if (promiseByKey.metadata[key].isRejected()) {
                                        output.nl().annotationBlock(function () {
                                            this.text(key).text(':').sp().append(promiseByKey.metadata[key].reason().getErrorMessage(output));
                                        });
                                    }
                                });
                                return output;
                            }
                        });
                    }
                });
            }).then(function () {
                if (nextCalls.length > 1) {
                    throw new Error('next called more than once');
                }
                done = true; // Tell the next function that subsequent calls should cause an exception to be thrown
                return context;
            });
        });
    }
};

module.exports.messy = messy;
<|endoftext|>


<commit_before>var assert = require("assert");

var mosto = require('../mosto.js');
var server = undefined;

//TODO: This test should be rewritten after @fabriciocosta merges his part with more usefull data!
describe('init mosto', function() {
    before(function(done) {
        server = new mosto('./test/mosto-status-test-config.json');
        done();
    });
    describe('#mosto server up', function() {
        it('--should be instantiated', function() {
            assert.notEqual(server, undefined);
        });
    });
});

describe('suscribe to status and wait 5 seconds', function() {
    this.timeout(6000);
    var rec = 0;
    before(function(done) {
        server.on('status', function(status) {
            console.log(status);
            rec++;
        });
        setTimeout(function() {
            done();
        }, 5500);
    });
    describe('#mosto status received', function() {
        it('--should have received 5 status events', function() {
            assert.equal(rec, 5);
        });
    });
});<commit_msg>Adding and fixing tests<commit_after>var assert = require("assert");

var mosto = require('../mosto.js');
var server = undefined;

//TODO: This test should be rewritten after @fabriciocosta merges his part with more usefull data!
describe('Mosto status', function() {
    before(function(done) {
        server = new mosto('./test/mosto-status-test-config.json');
        done();
    });

    describe('init mosto', function() {
        describe('#mosto server up', function() {
            it('--should be instantiated', function() {
                assert.notEqual(server, undefined);
            });
        });
    });

    describe('suscribe to status and wait 5 seconds', function() {
        it('--should have received 5 status events', function() {
            this.timeout(6000);
            var rec = 0;
            server.on('status', function(status) {
                if(++rec == 5) {
                    done();
                }
            });
        });
    });
});
<|endoftext|>


<commit_before>import css from 'css'
import { describe, it } from 'global-mocha'
import path from 'path'
import penthouse from '../lib/'
import { readFileSync as read } from 'fs'
import chai from 'chai'
chai.should() // binds globally on Object

describe('extra tests for penthouse node module', function () {
  var page1cssPath = path.join(__dirname, 'static-server', 'page1.css'),
    page1 = path.join(__dirname, 'static-server', 'page1.html')

  // phantomjs takes a while to start up
  this.timeout(5000)

  it('error should not contain debug info', function (done) {
    penthouse({
      url: 'http://localhost.does.not.exist',
      css: page1cssPath
    }, function (err, result) {
      if (err) {
        if (/^Error: time: 0/.test(err)) {
          done(err)
        } else {
          done()
        }
        return
      }
      done(new Error('did not return expected error'))
    })
  })

  it('error should contain debug in debug mode', function (done) {
    penthouse.DEBUG = true
    penthouse({
      url: 'http://localhost.does.not.exist',
      css: page1cssPath
    }, function (err, result) {
      if (err) {
        if (/^Error: time: /.test(err)) {
          done()
        } else {
          done(err)
        }
        return
      }
      done(new Error('did not have expected error'))
    })
  })
})
<commit_msg>improve comments around debug info test<commit_after>import css from 'css'
import { describe, it } from 'global-mocha'
import path from 'path'
import penthouse from '../lib/'
import { readFileSync as read } from 'fs'
import chai from 'chai'
chai.should() // binds globally on Object

describe('extra tests for penthouse node module', function () {
  var page1cssPath = path.join(__dirname, 'static-server', 'page1.css'),
    page1 = path.join(__dirname, 'static-server', 'page1.html')

  // phantomjs takes a while to start up
  this.timeout(5000)

  it('error should not contain debug info', function (done) {
    penthouse({
      url: 'http://localhost.does.not.exist',
      css: page1cssPath
    }, function (err, result) {
      if (err) {
        if (/^Error: time: 0/.test(err)) {
          done(err)
        } else {
          done()
        }
        return
      }
      done(new Error('did not return expected error'))
    })
  })

  it('error should contain debug info in debug mode', function (done) {
    penthouse.DEBUG = true
    penthouse({
      url: 'http://localhost.does.not.exist',
      css: page1cssPath
    }, function (err, result) {
      if (err) {
        // err should have format like:
        // time: 0 | opened css
        // time: 2 | parsed ast (without errors)
        if (/^Error: time: /.test(err)) {
          done()
        } else {
          done(err)
        }
        return
      }
      done(new Error('did not throw any error, which was expected'))
    })
  })
})
<|endoftext|>


<commit_before>const _ = require('lodash');

const execution = require('./execution');
const http = require('./http');

module.exports = (() => {
  const REVIEW_TOOLS = {
    github: {
      getPullRequestUrl (owner, repository) {
        return `https://api.github.com/repos/${owner}/${repository}/pulls`;
      },
      handleResponseError (response) {
        const message = _.get(response.body, 'message');
        if (message) {
          execution.exit(1, `GitHub API call failed with message: ${message}.`);
        }

        const error = _.get(response.body, 'errors[0]') || {};

        if (error.field === 'head') {
          execution.exit(1, 'It looks like your branch was not pushed to upstream.');

        } else if (error.message) {
          execution.exit(1, error.message);

        } else {
          execution.exit(1, `GitHub API call failed with status ${response.statusCode}.\nThe full error:\n${JSON.stringify(response.body, null, 2)}`);

        }
      },
      async createPullRequest (options) {
        const callOptions = {
          method: http.HTTP_METHODS.POST,
          headers: {
            Accept: 'application/json',
            Authorization: `Bearer ${options.pullRequestToken}`,
            'Content-Type': 'application/json'
          },
          json: true,
          body: {
            title: options.prTitle,
            head: options.currentBranch,
            base: options.baseBranch,
            body: options.description
          }
        };

        try {
          const response = await http.send(this.getPullRequestUrl(options.owner, options.repository), callOptions);
          if (response.statusCode < 299) {
            execution.print(`Your PR is available at ${response.body.html_url}`);

          } else {
            this.handleResponseError(response);

          }

        } catch (error) {
          execution.exit(1, `Impossible to create the PR:\n${error.stack}`);
        }
      }
    }
  };

  return { REVIEW_TOOLS };
})();
<commit_msg>:up: Better logs when GitHub API call fails<commit_after>const _ = require('lodash');

const execution = require('./execution');
const http = require('./http');

module.exports = (() => {
  const REVIEW_TOOLS = {
    github: {
      getPullRequestUrl (owner, repository) {
        return `https://api.github.com/repos/${owner}/${repository}/pulls`;
      },
      handleResponseError (response) {
        const message = _.get(response.body, 'message');
        const error = _.get(response.body, 'errors[0]') || {};

        if (message && _.isEmpty(error)) {
          execution.exit(1, `GitHub API call failed with message: ${message}.`);
        }

        if (error.field === 'head') {
          execution.exit(1, 'It looks like your branch was not pushed to upstream.');

        } else if (error.message) {
          execution.exit(1, error.message);

        } else {
          execution.exit(1, `GitHub API call failed with status ${response.statusCode}.\nThe full error:\n${JSON.stringify(response.body, null, 2)}`);

        }
      },
      async createPullRequest (options) {
        const callOptions = {
          method: http.HTTP_METHODS.POST,
          headers: {
            Accept: 'application/json',
            Authorization: `Bearer ${options.pullRequestToken}`,
            'Content-Type': 'application/json'
          },
          json: true,
          body: {
            title: options.prTitle,
            head: options.currentBranch,
            base: options.baseBranch,
            body: options.description
          }
        };

        try {
          const response = await http.send(this.getPullRequestUrl(options.owner, options.repository), callOptions);
          if (response.statusCode < 299) {
            execution.print(`Your PR is available at ${response.body.html_url}`);

          } else {
            this.handleResponseError(response);

          }

        } catch (error) {
          execution.exit(1, `Impossible to create the PR:\n${error.stack}`);
        }
      }
    }
  };

  return { REVIEW_TOOLS };
})();
<|endoftext|>


<commit_before>const test = require('tape');
const queryParams = require('../lib/query-params');

test('Should build a query param object from a html request', (t) => {
  t.plan(4);
  const query = {
    query: {
      q: 'ada',
      'fields[type]': 'people',
      'filter[occupation]': 'mathematician',
      'filter[birth[place]]': 'london',
      'filter[birth[date]]': '1800',
      'filter[death[date]]': '1900'
    },
    params: {}
  };

  const result = queryParams('html', query);

  t.equal(result.filter.people.birthPlace[0], 'london', 'filter with place equal "london"');
  t.equal(result.filter.people.birthDate, '1800', 'filter by birthDate with 1800');
  t.equal(result.filter.people.deathDate, '1900', 'filter by deathDate with 1900');
  t.equal(result.filter.people.occupation[0], 'mathematician', 'filter by occupation mathematician');
  t.end();
});

test('Should build a query param object from a json api request', (t) => {
  t.plan(6);
  const query = {
    query: {
      q: 'ada',
      'fields[type]': 'people',
      'filter[occupation]': 'mathematician,developer',
      'filter[birth[place]]': 'london,Paris',
      'filter[birth[date]]': '1800',
      'filter[death[date]]': '1900'
    },
    params: {}
  };

  const result = queryParams('json', query);
  t.equal(result.filter.people.birthPlace[0], 'london', 'filter with place equal "london"');
  t.equal(result.filter.people.birthPlace[1], 'Paris', 'filter with place equal "Paris"');
  t.equal(result.filter.people.birthDate, '1800', 'filter by birthDate with 1800');
  t.equal(result.filter.people.deathDate, '1900', 'filter by deathDate with 1900');
  t.equal(result.filter.people.occupation[0], 'mathematician', 'filter by occupation mathematician');
  t.equal(result.filter.people.occupation[1], 'developer', 'filter by occupation developer');
  t.end();
});
<commit_msg>add test for query-params, #112<commit_after>const test = require('tape');
const queryParams = require('../lib/query-params');

test('Should build a query param object from a html request', (t) => {
  t.plan(4);
  const query = {
    query: {
      q: 'ada',
      'fields[type]': 'people',
      'filter[occupation]': 'mathematician',
      'filter[birth[place]]': 'london',
      'filter[birth[date]]': '1800',
      'filter[death[date]]': '1900'
    },
    params: {}
  };

  const result = queryParams('html', query);

  t.equal(result.filter.people.birthPlace[0], 'london', 'filter with place equal "london"');
  t.equal(result.filter.people.birthDate, '1800', 'filter by birthDate with 1800');
  t.equal(result.filter.people.deathDate, '1900', 'filter by deathDate with 1900');
  t.equal(result.filter.people.occupation[0], 'mathematician', 'filter by occupation mathematician');
  t.end();
});

test('Should build a query param object from a json api request', (t) => {
  t.plan(6);
  const query = {
    query: {
      q: 'ada',
      'fields[type]': 'people',
      'filter[occupation]': 'mathematician,developer',
      'filter[birth[place]]': 'london,Paris',
      'filter[birth[date]]': '1800',
      'filter[death[date]]': '1900'
    },
    params: {}
  };

  const result = queryParams('json', query);
  t.equal(result.filter.people.birthPlace[0], 'london', 'filter with place equal "london"');
  t.equal(result.filter.people.birthPlace[1], 'Paris', 'filter with place equal "Paris"');
  t.equal(result.filter.people.birthDate, '1800', 'filter by birthDate with 1800');
  t.equal(result.filter.people.deathDate, '1900', 'filter by deathDate with 1900');
  t.equal(result.filter.people.occupation[0], 'mathematician', 'filter by occupation mathematician');
  t.equal(result.filter.people.occupation[1], 'developer', 'filter by occupation developer');
  t.end();
});

test('Should build a query param object with the value if the format is not html or json', (t) => {
  t.plan(1);
  const query = {
    query: {
      q: 'ada',
      'fields[type]': 'people',
      'filter[occupation]': 'mathematician,developer'
    },
    params: {}
  };

  const result = queryParams('wrongFormat', query);
  t.equal(result.filter.people.occupation, 'mathematician,developer', 'filter by occupation is null');
  t.end();
});
<|endoftext|>


<commit_before>'use babel';
/**
  Eval Console
  @description Provides a console where user can enter input in order to
    evaluate Go expressions within the current scope of the debugger in
    a REPL-esque style

  TODO: We will need to listen for the enter key from the input element,
    after hitting enter:
    - send to DebuggerActions.evalExpression (should return promise w/ result)
    - get result & write under the input (need to figure out how we're going to
        pretty print the resulting Go code)
    - disable the "spent" input element
    - create a new input element at the bottom of the console

  TODO: for the eval console input we might want to use a textarea to allow
    the user to type in multiple lines
**/

/* eslint no-unused-vars:0 */
import { createClass as createJSX, jsx } from 'vanilla-jsx';

/** @jsx jsx */
const DelveExprVal = createJSX({
  renderView(val) {
    return
{val}
;
  }
});

/** @jsx jsx */
const EvalConsoleElement = createJSX({
  createEvalInput() {
    return (

        <input type="text" class="delve-terminal-input delve-eval-textbox cur-input" />

    );
  },

  renderView() {
    return (

Eval Console

        {this.createEvalInput()}

    );
  },

  addExpressionValue(val) {
    let outputComp = new DelveExprVal();
    let $val = outputComp.render(val);

    this.element.appendChild($val);
  }
});

export default class EvalConsole {
  constructor() {
    this.consoleElement = new EvalConsoleElement();
    this.evalConsole = this.consoleElement.render();
    this.$curInput =
      this.evalConsole.querySelector('.delve-eval-textbox.cur-input');

    this.$curInput
    .addEventListener('keyup', this.sendEvalExpr.bind(this), true);
  }

  sendEvalExpr(evt) {
    if (evt.code !== 'Enter' || evt.shiftKey || !this.$curInput) return;

    const expression = this.$curInput.value.trim();

    atom.notifications.addInfo(
      'Would normally eval the expression', { detail: expression }
    );

    // NOTE: temporary
    const val = '&interface{}';
    this.consoleElement.addExpressionValue(val);

    // TODO: create a new eval input, disable the old one, update our $curInput
    // and then add the event listener back on
    // might need to create another component for eval inputs
    this.$curInput.disabled = true;
    this.$curInput.classList.remove('cur-input');

    evt.preventDefault();
  }

  getElement() {
    return this.evalConsole;
  }

  destroy() {
    this.consoleElement.dispose();
  }
}
<commit_msg>Create new eval input after eval, move to separate component<commit_after>'use babel';
/**
  Eval Console
  @description Provides a console where user can enter input in order to
    evaluate Go expressions within the current scope of the debugger in
    a REPL-esque style

  TODO: We will need to listen for the enter key from the input element,
    after hitting enter:
    - send to DebuggerActions.evalExpression (should return promise w/ result)
    - get result & write under the input (need to figure out how we're going to
        pretty print the resulting Go code)
    - disable the "spent" input element
    - create a new input element at the bottom of the console

  TODO: for the eval console input we might want to use a textarea to allow
    the user to type in multiple lines
**/

/* eslint no-unused-vars:0 */
import { createClass as createJSX, jsx } from 'vanilla-jsx';

/** @jsx jsx */
const DelveExprVal = createJSX({
  renderView(val) {
    return
{val}
;
  }
});

/** @jsx jsx */
const DelveEvalInput = createJSX({
  renderView() {
    return (

        <input type="text" class="delve-terminal-input delve-eval-textbox cur-input" />

    );
  },

  deactivate() {
    this.element.children[0].disabled = true;
    this.element.children[0].classList.remove('cur-input');
  }
});

/** @jsx jsx */
const EvalConsoleElement = createJSX({
  renderView() {
    return (

Eval Console

    );
  },

  addExpressionValue(val) {
    let outputComp = new DelveExprVal();
    let $val = outputComp.render(val);

    this.element.appendChild($val);
  },

  addNewEvalInput() {
    if (this.curInput) this.curInput.deactivate();
    let newInput = new DelveEvalInput();
    this.element.appendChild(newInput.render());
    this.curInput = newInput;

    // first child is always the <input /> itself
    return newInput.element.children[0];
  }
});

export default class EvalConsole {
  constructor() {
    this.consoleElement = new EvalConsoleElement();
    this.evalConsole = this.consoleElement.render();
    this.$curInput = this.consoleElement.addNewEvalInput();

    this.$curInput
    .addEventListener('keyup', this.sendEvalExpr.bind(this), true);
  }

  sendEvalExpr(evt) {
    if (evt.code !== 'Enter' || evt.shiftKey || !this.$curInput) return;

    const expression = this.$curInput.value.trim();

    atom.notifications.addInfo(
      'Would normally eval the expression', { detail: expression }
    );

    // NOTE: temporary
    const val = '&interface{}';
    this.consoleElement.addExpressionValue(val);
    this.$curInput = this.consoleElement.addNewEvalInput();

    this.$curInput
    .addEventListener('keyup', this.sendEvalExpr.bind(this), true);

    evt.preventDefault();
  }

  getElement() {
    return this.evalConsole;
  }

  destroy() {
    this.consoleElement.dispose();
  }
}
<|endoftext|>


<commit_before>
var assert = require('assert');
var carto = require('../lib/carto');

describe('RenderingJS', function() {
  var shader;
  var style = [
  '#world {',
    'line-width: 2;',
    'line-color: #f00;',
    '[frame-offset = 1] {',
      'line-width: 3;',
    '}',
    '[frame-offset = 2] {',
      'line-width: 3;',
    '}',
  '}',
  '',
  '#worls[frame-offset = 10] {',
      'line-width: 4;',
  '}'
  ].join('\n');

  beforeEach(function() {
    shader = (new carto.RendererJS({ debug: true })).render(style);
  });

  it ("shold render layers", function() {
    assert(shader.getLayers().length === 2);
  });

  it ("shold report frames used in the layer", function() {
    var layer = shader.getLayers()[0];
    assert( layer.frames()[0] === 0);
    assert( layer.frames()[1] === 1);

    layer = shader.getLayers()[1];
    assert( layer.frames()[0] === 10);
  });

  it ("shold render with frames var", function() {
    var layer = shader.getLayers()[1];
    var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['line-width'] === 4);
  });

  it ("shold render variables", function() {
    var style = '#test { marker-width: [testing]; }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({testing: 2}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['marker-width'] === 2);
  });

  it ("should allow filter based rendering", function() {
    var style = '#test { marker-width: 10; [zoom = 1] { marker-width: 1; } }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['marker-width'] ===  10);
    props = layer.getStyle({}, { 'zoom': 1, 'frame-offset': 10 });
    assert( props['marker-width'] ===  1);
  });

  it ("symbolizers should be in rendering order", function() {
    var style = '#test { polygon-fill: red; line-color: red; }';
    style += '#test2 { line-color: red;polygon-fill: red; line-width: 10; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    assert(layer0.getSymbolizers()[0] === 'polygon');
    assert(layer0.getSymbolizers()[1] === 'line');

    var layer1 = shader.getLayers()[1];
    assert(layer0.getSymbolizers()[0] === 'polygon');
    assert(layer0.getSymbolizers()[1] === 'line');
  });

  it ("colorize should return a list of colours in same order", function() {
    var style = '#test { image-filters: colorize-alpha(blue, cyan, green, yellow, orange, red); }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    var st = layer0.getStyle({ value: 1 }, {"frame-offset": 0, "zoom": 3});
    var expectedColours = [[0, 0, 255], [0, 255, 255], [0, 128, 0], [255, 255, 0], [255, 165, 0], [255, 0, 0]];
    for (var i = 0; i < st["image-filters"].args; i++){
      assert (st["image-filters"].args[i].rgb === expectedColours[i]);
    }
  });

  it ("should return list of marker-files", function(){
    var css = [
          'Map {',
          '-torque-time-attribute: "date";',
          '-torque-aggregation-function: "count(cartodb_id)";',
          '-torque-frame-count: 760;',
          '-torque-animation-duration: 15;',
          '-torque-resolution: 2;',
          '}',
          '#layer {',
          '  marker-width: 3;',
          '  marker-fill-opacity: 0.8;',
          '  marker-fill: #FEE391; ',
          '  marker-file: url(http://localhost:8081/gal.svg); ',
          '  comp-op: "lighten";',
          '  [value > 2] { marker-file: url(http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg); }',
          '  [value > 3] { marker-file: url(http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg); }',
          '  [frame-offset = 1] { marker-width: 10; marker-fill-opacity: 0.05;}',
          '  [frame-offset = 2] { marker-width: 15; marker-fill-opacity: 0.02;}',
          '}'
      ].join('\n');
      var shader = (new carto.RendererJS({ debug: true })).render(css);
      var markerURLs = shader.getImageURLs();
      var against = ["http://localhost:8081/gal.svg", "http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg", "http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg"];
      for(var i = 0; i<against.length; i++){
        assert(against[i] == markerURLs[i])
      }
  })

  it ("should return variable for styles that change", function() {
    var style = '#test { marker-width: [prop]; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    assert(layer0.isVariable());

    style = '#test { marker-width: 1; }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    layer0 = shader.getLayers()[0];
    assert(!layer0.isVariable());

    style = '#test { marker-width: [prop]; marker-fill: red;  }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    layer0 = shader.getLayers()[0];
    assert(layer0.isVariable());
  });

  it("should parse styles with string", function() {
    var style = '#test { [column = "test\'ing"] { marker-width: 10; } }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({column: 'test\'ing'}, {  'zoom': 0, 'frame-offset': 10 });
    assert(props['marker-width'] ===  10);
  });

  it("should parse styles with filters not supported by dot notation", function() {
    var style = '#test["mapnik::geometry_type"=1] { marker-width: 10; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({"mapnik::geometry_type": 1}, { 'zoom': 0 });
    assert.equal(props['marker-width'], 10);
    var emptyFilterProps = layer.getStyle({"mapnik::geometry_type": 2}, { 'zoom': 0 });
    assert.equal(emptyFilterProps['marker-width'], null);
  });

  it ("should parse turbocarto", function(){
    var css = [
          '#layer {',
          '  marker-width: ramp([cartodb_id], (#fff, #bbb), jenks);',
          '}'
      ].join('\n');
      var shader = (new carto.RendererJS({ debug: true })).render(css);
      var layer = shader.getLayers()[0];
      var st = layer.shader['marker-width'].style({}, {zoom: 1})
      assert.equal(st.name, "ramp")
      assert.equal(st.args.length, 3);
      assert.equal(st.args[1].value[0].rgb[0], 255);
      assert.equal(st.args[1].value[0].rgb[1], 255);
      assert.equal(st.args[1].value[0].rgb[2], 255);
      assert.equal(st.args[2].value, 'jenks');
  })

  it("should parse turbocarto with inner functions", function(){
    var css = [
      '#layer {',
      '  marker-width: ramp([cartodb_id], cartocolor(Bold), category(10));',
      '}'
    ].join('\n');
    var shader = (new carto.RendererJS({ debug: true })).render(css);
    var layer = shader.getLayers()[0];
    var st = layer.shader['marker-width'].style({}, {zoom: 1});
    assert.equal(st.name, "ramp");
    assert.equal(st.args.length, 3);
    assert.equal(st.args[1].name, 'cartocolor');
    assert.equal(st.args[1].args[0].value, 'Bold');
    assert.equal(st.args[2].name, 'category');
    assert.equal(st.args[2].args[0].value, 10);
  });

});
<commit_msg>Revert changes not needed for PR<commit_after>
var assert = require('assert');
var carto = require('../lib/carto');

describe('RenderingJS', function() {
  var shader;
  var style = [
  '#world {',
    'line-width: 2;',
    'line-color: #f00;',
    '[frame-offset = 1] {',
      'line-width: 3;',
    '}',
    '[frame-offset = 2] {',
      'line-width: 3;',
    '}',
  '}',
  '',
  '#worls[frame-offset = 10] {',
      'line-width: 4;',
  '}'
  ].join('\n');

  beforeEach(function() {
    shader = (new carto.RendererJS({ debug: true })).render(style);
  });

  it ("shold render layers", function() {
    assert(shader.getLayers().length === 2);
  });

  it ("shold report frames used in the layer", function() {
    var layer = shader.getLayers()[0];
    assert( layer.frames()[0] === 0);
    assert( layer.frames()[1] === 1);

    layer = shader.getLayers()[1];
    assert( layer.frames()[0] === 10);
  });

  it ("shold render with frames var", function() {
    var layer = shader.getLayers()[1];
    var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['line-width'] === 4);
  });

  it ("shold render variables", function() {
    var style = '#test { marker-width: [testing]; }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({testing: 2}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['marker-width'] === 2);
  });

  it ("should allow filter based rendering", function() {
    var style = '#test { marker-width: 10; [zoom = 1] { marker-width: 1; } }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({}, { 'zoom': 0, 'frame-offset': 10 });
    assert( props['marker-width'] ===  10);
    props = layer.getStyle({}, { 'zoom': 1, 'frame-offset': 10 });
    assert( props['marker-width'] ===  1);
  });

  it ("symbolizers should be in rendering order", function() {
    var style = '#test { polygon-fill: red; line-color: red; }';
    style += '#test2 { line-color: red;polygon-fill: red; line-width: 10; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    assert(layer0.getSymbolizers()[0] === 'polygon');
    assert(layer0.getSymbolizers()[1] === 'line');

    var layer1 = shader.getLayers()[1];
    assert(layer0.getSymbolizers()[0] === 'polygon');
    assert(layer0.getSymbolizers()[1] === 'line');
  });

  it ("colorize should return a list of colours in same order", function() {
    var style = '#test { image-filters: colorize-alpha(blue, cyan, green, yellow, orange, red); }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    var st = layer0.getStyle({ value: 1 }, {"frame-offset": 0, "zoom": 3});
    var expectedColours = [[0, 0, 255], [0, 255, 255], [0, 128, 0], [255, 255, 0], [255, 165, 0], [255, 0, 0]];
    for (var i = 0; i < st["image-filters"].args; i++){
      assert (st["image-filters"].args[i].rgb === expectedColours[i]);
    }
  });

  it ("should return list of marker-files", function(){
    var css = [
          'Map {',
          '-torque-time-attribute: "date";',
          '-torque-aggregation-function: "count(cartodb_id)";',
          '-torque-frame-count: 760;',
          '-torque-animation-duration: 15;',
          '-torque-resolution: 2',
          '}',
          '#layer {',
          '  marker-width: 3;',
          '  marker-fill-opacity: 0.8;',
          '  marker-fill: #FEE391; ',
          '  marker-file: url(http://localhost:8081/gal.svg); ',
          '  comp-op: "lighten";',
          '  [value > 2] { marker-file: url(http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg); }',
          '  [value > 3] { marker-file: url(http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg); }',
          '  [frame-offset = 1] { marker-width: 10; marker-fill-opacity: 0.05;}',
          '  [frame-offset = 2] { marker-width: 15; marker-fill-opacity: 0.02;}',
          '}'
      ].join('\n');
      var shader = (new carto.RendererJS({ debug: true })).render(css);
      var markerURLs = shader.getImageURLs();
      var against = ["http://localhost:8081/gal.svg", "http://upload.wikimedia.org/wikipedia/commons/4/43/Flag_of_the_Galactic_Empire.svg", "http://upload.wikimedia.org/wikipedia/commons/c/c9/Flag_of_Syldavia.svg"];
      for(var i = 0; i<against.length; i++){
        assert(against[i] == markerURLs[i])
      }
  })

  it ("should return variable for styles that change", function() {
    var style = '#test { marker-width: [prop]; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer0 = shader.getLayers()[0];
    assert(layer0.isVariable());

    style = '#test { marker-width: 1; }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    layer0 = shader.getLayers()[0];
    assert(!layer0.isVariable());

    style = '#test { marker-width: [prop]; marker-fill: red;  }';
    shader = (new carto.RendererJS({ debug: true })).render(style);
    layer0 = shader.getLayers()[0];
    assert(layer0.isVariable());
  });

  it("should parse styles with string", function() {
    var style = '#test { [column = "test\'ing"] { marker-width: 10; } }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({column: 'test\'ing'}, {  'zoom': 0, 'frame-offset': 10 });
    assert(props['marker-width'] ===  10);
  });

  it("should parse styles with filters not supported by dot notation", function() {
    var style = '#test["mapnik::geometry_type"=1] { marker-width: 10; }';
    var shader = (new carto.RendererJS({ debug: true })).render(style);
    var layer = shader.getLayers()[0];
    var props = layer.getStyle({"mapnik::geometry_type": 1}, { 'zoom': 0 });
    assert.equal(props['marker-width'], 10);
    var emptyFilterProps = layer.getStyle({"mapnik::geometry_type": 2}, { 'zoom': 0 });
    assert.equal(emptyFilterProps['marker-width'], null);
  });

  it ("should parse turbocarto", function(){
    var css = [
          '#layer {',
          '  marker-width: ramp([cartodb_id], (#fff, #bbb), jenks);',
          '}'
      ].join('\n');
      var shader = (new carto.RendererJS({ debug: true })).render(css);
      var layer = shader.getLayers()[0];
      var st = layer.shader['marker-width'].style({}, {zoom: 1})
      assert.equal(st.name, "ramp")
      assert.equal(st.args.length, 3);
      assert.equal(st.args[1].value[0].rgb[0], 255);
      assert.equal(st.args[1].value[0].rgb[1], 255);
      assert.equal(st.args[1].value[0].rgb[2], 255);
      assert.equal(st.args[2].value, 'jenks');
  })

  it("should parse turbocarto with inner functions", function(){
    var css = [
      '#layer {',
      '  marker-width: ramp([cartodb_id], cartocolor(Bold), category(10));',
      '}'
    ].join('\n');
    var shader = (new carto.RendererJS({ debug: true })).render(css);
    var layer = shader.getLayers()[0];
    var st = layer.shader['marker-width'].style({}, {zoom: 1});
    assert.equal(st.name, "ramp");
    assert.equal(st.args.length, 3);
    assert.equal(st.args[1].name, 'cartocolor');
    assert.equal(st.args[1].args[0].value, 'Bold');
    assert.equal(st.args[2].name, 'category');
    assert.equal(st.args[2].args[0].value, 10);
  });

});
<|endoftext|>