<commit_before>exports.test_data = {
    default_options: [
        { name: "indent_size", value: "1" },
        { name: "indent_char", value: "'\\t'" },
        { name: "selector_separator_newline", value: "true" },
        { name: "end_with_newline", value: "false" },
        { name: "newline_between_rules", value: "false" },
    ],
    groups: [{
        name: "End With Newline",
        description: "",
        matrix: [{
            options: [
                { name: "end_with_newline", value: "true" }
            ],
            eof: '\\n'
        }, {
            options: [
                { name: "end_with_newline", value: "false" }
            ],
            eof: ''
        }],
        tests: [
            { fragment: true, input: '', output: '{{eof}}' },
            { fragment: true, input: '   .tabs{}', output: '   .tabs {}{{eof}}' },
            { fragment: true, input: '   \n\n.tabs{}\n\n\n\n', output: '   .tabs {}{{eof}}' },
            { fragment: true, input: '\n', output: '{{eof}}' }
        ],
    }, {
        name: "Empty braces",
        description: "",
        tests: [
            { input: '.tabs{}', output: '.tabs {}' },
            { input: '.tabs { }', output: '.tabs {}' },
            { input: '.tabs    {    }', output: '.tabs {}' },
            // When we support preserving newlines this will need to change
            { input: '.tabs    \n{\n    \n  }', output: '.tabs {}' }
        ],
    }, {
        name: "",
        description: "",
        tests: [{
            input: '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity = 90);\n}',
            output: '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity=90);\n}'
        }, ],
    }, {
        name: 'Selector Separator',
        description: '',
        matrix: [{
            options: [
                { name: 'selector_separator_newline', value: 'false' },
                { name: 'selector_separator', value: '" "' }
            ],
            separator: ' ',
            separator1: ' '
        }, {
            options: [
                { name: 'selector_separator_newline', value: 'false' },
                { name: 'selector_separator', value: '"  "' }
            ],
            // BUG: #713
            separator: ' ',
            separator1: ' '
        }, {
            options: [
                { name: 'selector_separator_newline', value: 'true' },
                { name: 'selector_separator', value: '" "' }
            ],
            separator: '\\n',
            separator1: '\\n\\t'
        }, {
            options: [
                { name: 'selector_separator_newline', value: 'true' },
                { name: 'selector_separator', value: '"  "' }
            ],
            separator: '\\n',
            separator1: '\\n\\t'
        }],
        tests: [
            { input: '#bla, #foo{color:green}', output: '#bla,{{separator}}#foo {\n\tcolor: green\n}' },
            { input: '@media print {.tab{}}', output: '@media print {\n\t.tab {}\n}' },
            { input: '@media print {.tab,.bat{}}', output: '@media print {\n\t.tab,{{separator1}}.bat {}\n}' },
            { input: '#bla, #foo{color:black}', output: '#bla,{{separator}}#foo {\n\tcolor: black\n}' }, {
                input: 'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}',
                output: 'a:first-child,{{separator}}a:first-child {\n\tcolor: red;\n\tdiv:first-child,{{separator1}}div:hover {\n\t\tcolor: black;\n\t}\n}'
            }
        ]
    }, {
        name: "Newline Between Rules",
        description: "",
        matrix: [{
            options: [
                { name: "newline_between_rules", value: "true" }
            ],
            separator: '\\n'
        }, {
            options: [
                { name: "newline_between_rules", value: "false" }
            ],
            separator: ''
        }],
        tests: [
            { input: '.div {}\n.span {}', output: '.div {}\n{{separator}}.span {}' },
            { input: '.div{}\n   \n.span{}', output: '.div {}\n{{separator}}.span {}' },
            { input: '.div {}    \n  \n.span { } \n', output: '.div {}\n{{separator}}.span {}' },
            { input: '.div {\n    \n} \n  .span {\n }  ', output: '.div {}\n{{separator}}.span {}' },
            { input: '.selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n.div{height:15px;}', output: '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: '.tabs{width:10px;//end of line comment\nheight:10px;//another\n}\n.div{height:15px;}', output: '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', output: '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', output: '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}', output: '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n{{separator}}@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}' },
            { input: 'a:first-child{color:red;div:first-child{color:black;}}\n.div{height:15px;}', output: 'a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: 'a:first-child{color:red;div:not(.peq){color:black;}}\n.div{height:15px;}', output: 'a:first-child {\n\tcolor: red;\n\tdiv:not(.peq) {\n\t\tcolor: black;\n\t}\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
        ],
    }, {
        name: "Functions braces",
        description: "",
        tests: [
            { input: '.tabs(){}', output: '.tabs() {}' },
            { input: '.tabs (){}', output: '.tabs () {}' },
            { input: '.tabs (pa, pa(1,2)), .cols { }', output: '.tabs (pa, pa(1, 2)),\n.cols {}' },
            { input: '.tabs(pa, pa(1,2)), .cols { }', output: '.tabs(pa, pa(1, 2)),\n.cols {}' },
            { input: '.tabs (   )   {    }', output: '.tabs () {}' },
            { input: '.tabs(   )   {    }', output: '.tabs() {}' },
            { input: '.tabs  (t, t2)  \n{\n  key: val(p1  ,p2);  \n  }', output: '.tabs (t, t2) {\n\tkey: val(p1, p2);\n}' },
            { input: '.box-shadow(@shadow: 0 1px 3px rgba(0, 0, 0, .25)) {\n\t-webkit-box-shadow: @shadow;\n\t-moz-box-shadow: @shadow;\n\tbox-shadow: @shadow;\n}' }
        ],
    }, {
        name: "Comments",
        description: "",
        tests: [
            { unchanged: '/* test */' },
            { input: '.tabs{/* test */}', output: '.tabs {\n\t/* test */\n}' },
            { input: '.tabs{/* test */}', output: '.tabs {\n\t/* test */\n}' },
            { input: '/* header */.tabs {}', output: '/* header */\n\n.tabs {}' },
            { input: '.tabs {\n/* non-header */\nwidth:10px;}', output: '.tabs {\n\t/* non-header */\n\twidth: 10px;\n}' },
            { unchanged: '/* header' },
            { unchanged: '// comment' }, {
                input: '.selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}',
                output: '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}'
            },

            {
                comment: "single line comment support (less/sass)",
                input: '.tabs{\n// comment\nwidth:10px;\n}',
                output: '.tabs {\n\t// comment\n\twidth: 10px;\n}'
            },
            { input: '.tabs{// comment\nwidth:10px;\n}', output: '.tabs {\n\t// comment\n\twidth: 10px;\n}' },
            { input: '//comment\n.tabs{width:10px;}', output: '//comment\n.tabs {\n\twidth: 10px;\n}' },
            { input: '.tabs{//comment\n//2nd single line comment\nwidth:10px;}', output: '.tabs {\n\t//comment\n\t//2nd single line comment\n\twidth: 10px;\n}' },
            { input: '.tabs{width:10px;//end of line comment\n}', output: '.tabs {\n\twidth: 10px; //end of line comment\n}' },
            { input: '.tabs{width:10px;//end of line comment\nheight:10px;}', output: '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px;\n}' },
            { input: '.tabs{width:10px;//end of line comment\nheight:10px;//another\n}', output: '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}' }
        ],
    }, {
        name: "Handle LESS properties",
        description: "",
        tests: [
            { unchanged: 'tag {\n\t@{prop}: none;\n}' }
        ],
    }, {
        name: "Psuedo-classes vs Variables",
        description: "",
        tests: [
            { unchanged: '@page :first {}' }, {
                comment: "Assume the colon goes with the @name. If we're in LESS, this is required regardless of the at-string.",
                input: '@page:first {}',
                output: '@page: first {}'
            },
            { unchanged: '@page: first {}' }
        ],
    }, {
        name: "SASS/SCSS",
        description: "",
        tests: [{
                comment: "Basic Interpolation",
                unchanged: 'p {\n\t$font-size: 12px;\n\t$line-height: 30px;\n\tfont: #{$font-size}/#{$line-height};\n}'
            },
            { unchanged: 'p.#{$name} {}' }, {
                unchanged: [
                    '@mixin itemPropertiesCoverItem($items, $margin) {',
                    '\twidth: calc((100% - ((#{$items} - 1) * #{$margin}rem)) / #{$items});',
                    '\tmargin: 1.6rem #{$margin}rem 1.6rem 0;',
                    '}'
                ]
            }
        ],
    }, {

    }]
};
<commit_msg>Build succeeds locally but needs newline fix to pass checks<commit_after>exports.test_data = {
    default_options: [
        { name: "indent_size", value: "1" },
        { name: "indent_char", value: "'\\t'" },
        { name: "selector_separator_newline", value: "true" },
        { name: "end_with_newline", value: "false" },
        { name: "newline_between_rules", value: "false" },
    ],
    groups: [{
        name: "End With Newline",
        description: "",
        matrix: [{
            options: [
                { name: "end_with_newline", value: "true" }
            ],
            eof: '\\n'
        }, {
            options: [
                { name: "end_with_newline", value: "false" }
            ],
            eof: ''
        }],
        tests: [
            { fragment: true, input: '', output: '{{eof}}' },
            { fragment: true, input: '   .tabs{}', output: '   .tabs {}{{eof}}' },
            { fragment: true, input: '   \n\n.tabs{}\n\n\n\n', output: '   .tabs {}{{eof}}' },
            { fragment: true, input: '\n', output: '{{eof}}' }
        ],
    }, {
        name: "Empty braces",
        description: "",
        tests: [
            { input: '.tabs{}', output: '.tabs {}' },
            { input: '.tabs { }', output: '.tabs {}' },
            { input: '.tabs    {    }', output: '.tabs {}' },
            // When we support preserving newlines this will need to change
            { input: '.tabs    \n{\n    \n  }', output: '.tabs {}' }
        ],
    }, {
        name: "",
        description: "",
        tests: [{
            input: '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity = 90);\n}',
            output: '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity=90);\n}'
        }, ],
    }, {
        name: 'Selector Separator',
        description: '',
        matrix: [{
            options: [
                { name: 'selector_separator_newline', value: 'false' },
                { name: 'selector_separator', value: '" "' }
            ],
            separator: ' ',
            separator1: ' '
        }, {
            options: [
                { name: 'selector_separator_newline', value: 'false' },
                { name: 'selector_separator', value: '"  "' }
            ],
            // BUG: #713
            separator: ' ',
            separator1: ' '
        }, {
            options: [
                { name: 'selector_separator_newline', value: 'true' },
                { name: 'selector_separator', value: '" "' }
            ],
            separator: '\\n',
            separator1: '\\n\\t'
        }, {
            options: [
                { name: 'selector_separator_newline', value: 'true' },
                { name: 'selector_separator', value: '"  "' }
            ],
            separator: '\\n',
            separator1: '\\n\\t'
        }],
        tests: [
            { input: '#bla, #foo{color:green}', output: '#bla,{{separator}}#foo {\n\tcolor: green\n}' },
            { input: '@media print {.tab{}}', output: '@media print {\n\t.tab {}\n}' },
            { input: '@media print {.tab,.bat{}}', output: '@media print {\n\t.tab,{{separator1}}.bat {}\n}' },
            { input: '#bla, #foo{color:black}', output: '#bla,{{separator}}#foo {\n\tcolor: black\n}' }, {
                input: 'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}',
                output: 'a:first-child,{{separator}}a:first-child {\n\tcolor: red;\n\tdiv:first-child,{{separator1}}div:hover {\n\t\tcolor: black;\n\t}\n}'
            }
        ]
    }, {
        name: "Newline Between Rules",
        description: "",
        matrix: [{
            options: [
                { name: "newline_between_rules", value: "true" }
            ],
            separator: '\\n'
        }, {
            options: [
                { name: "newline_between_rules", value: "false" }
            ],
            separator: ''
        }],
        tests: [
            { input: '.div {}\n.span {}', output: '.div {}\n{{separator}}.span {}' },
            { input: '.div{}\n   \n.span{}', output: '.div {}\n{{separator}}.span {}' },
            { input: '.div {}    \n  \n.span { } \n', output: '.div {}\n{{separator}}.span {}' },
            { input: '.div {\n    \n} \n  .span {\n }  ', output: '.div {}\n{{separator}}.span {}' },
            { input: '.selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n.div{height:15px;}', output: '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: '.tabs{width:10px;//end of line comment\nheight:10px;//another\n}\n.div{height:15px;}', output: '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', output: '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', output: '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}', output: '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n{{separator}}@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}' },
            { input: 'a:first-child{color:red;div:first-child{color:black;}}\n.div{height:15px;}', output: 'a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
            { input: 'a:first-child{color:red;div:not(.peq){color:black;}}\n.div{height:15px;}', output: 'a:first-child {\n\tcolor: red;\n\tdiv:not(.peq) {\n\t\tcolor: black;\n\t}\n}\n{{separator}}.div {\n\theight: 15px;\n}' },
        ],
    }, {
        name: "Functions braces",
        description: "",
        tests: [
            { input: '.tabs(){}', output: '.tabs() {}' },
            { input: '.tabs (){}', output: '.tabs () {}' },
            { input: '.tabs (pa, pa(1,2)), .cols { }', output: '.tabs (pa, pa(1, 2)),\n.cols {}' },
            { input: '.tabs(pa, pa(1,2)), .cols { }', output: '.tabs(pa, pa(1, 2)),\n.cols {}' },
            { input: '.tabs (   )   {    }', output: '.tabs () {}' },
            { input: '.tabs(   )   {    }', output: '.tabs() {}' },
            { input: '.tabs  (t, t2)  \n{\n  key: val(p1  ,p2);  \n  }', output: '.tabs (t, t2) {\n\tkey: val(p1, p2);\n}' },
            { input: '.box-shadow(@shadow: 0 1px 3px rgba(0, 0, 0, .25)) {\n\t-webkit-box-shadow: @shadow;\n\t-moz-box-shadow: @shadow;\n\tbox-shadow: @shadow;\n}' }
        ],
    }, {
        name: "Comments",
        description: "",
        tests: [
            { unchanged: '/* test */' },
            { input: '.tabs{/* test */}', output: '.tabs {\n\t/* test */\n}' },
            { input: '.tabs{/* test */}', output: '.tabs {\n\t/* test */\n}' },
            { input: '/* header */.tabs {}', output: '/* header */\n\n.tabs {}' },
            { input: '.tabs {\n/* non-header */\nwidth:10px;}', output: '.tabs {\n\t/* non-header */\n\twidth: 10px;\n}' },
            { unchanged: '/* header' },
            { unchanged: '// comment' }, {
                input: '.selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}',
                output: '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}'
            },

            {
                comment: "single line comment support (less/sass)",
                input: '.tabs{\n// comment\nwidth:10px;\n}',
                output: '.tabs {\n\t// comment\n\twidth: 10px;\n}'
            },
            { input: '.tabs{// comment\nwidth:10px;\n}', output: '.tabs {\n\t// comment\n\twidth: 10px;\n}' },
            { input: '//comment\n.tabs{width:10px;}', output: '//comment\n.tabs {\n\twidth: 10px;\n}' },
            { input: '.tabs{//comment\n//2nd single line comment\nwidth:10px;}', output: '.tabs {\n\t//comment\n\t//2nd single line comment\n\twidth: 10px;\n}' },
            { input: '.tabs{width:10px;//end of line comment\n}', output: '.tabs {\n\twidth: 10px; //end of line comment\n}' },
            { input: '.tabs{width:10px;//end of line comment\nheight:10px;}', output: '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px;\n}' },
            { input: '.tabs{width:10px;//end of line comment\nheight:10px;//another\n}', output: '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}' }
        ],
    }, {
        name: "Handle LESS properties",
        description: "",
        tests: [
            { unchanged: 'tag {\n\t@{prop}: none;\n}' }
        ],
    }, {
        name: "Psuedo-classes vs Variables",
        description: "",
        tests: [
            { unchanged: '@page :first {}' }, {
                comment: "Assume the colon goes with the @name. If we're in LESS, this is required regardless of the at-string.",
                input: '@page:first {}',
                output: '@page: first {}'
            },
            { unchanged: '@page: first {}' }
        ],
    }, {
        name: "SASS/SCSS",
        description: "",
        tests: [{
                comment: "Basic Interpolation",
                unchanged: 'p {\n\t$font-size: 12px;\n\t$line-height: 30px;\n\tfont: #{$font-size}/#{$line-height};\n}'
            },
            { unchanged: 'p.#{$name} {}' }, {
                unchanged: [
                    '@mixin itemPropertiesCoverItem($items, $margin) {',
                    '\twidth: calc((100% - ((#{$items} - 1) * #{$margin}rem)) / #{$items});',
                    '\tmargin: 1.6rem #{$margin}rem 1.6rem 0;',
                    '}'
                ]
            }
        ],
    }, {

    }]
};<|endoftext|>


<commit_before>// For authoring Nightwatch tests, see
// http://nightwatchjs.org/guide#usage

module.exports = {
  'default e2e tests': function (browser) {
    // automatically uses dev Server port from /config.index.js
    // default: http://localhost:8080
    // see nightwatch.conf.js
    const devServer = browser.globals.devServerURL

    browser
      .url(devServer)
      .waitForElementVisible('#app', 5000)
      .assert.elementPresent('#background')
      .end()
  }
}
<commit_msg>e2e test fixed<commit_after>// For authoring Nightwatch tests, see
// http://nightwatchjs.org/guide#usage

module.exports = {
  'default e2e tests': function (browser) {
    // automatically uses dev Server port from /config.index.js
    // default: http://localhost:8080
    // see nightwatch.conf.js
    const devServer = browser.globals.devServerURL

    browser
      .url(devServer)
      .waitForElementVisible('#app', 5000)
      .assert.elementPresent('#img-background')
      .end()
  }
}
<|endoftext|>


<commit_before>import blacklist from 'blacklist';
import classNames from 'classnames';
import ErrorView from './ErrorView';
import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';

function createViewsFromChildren (children) {
	var views = {};
	React.Children.forEach(children, function (view) {
		views[view.props.name] = view;
	});
	return views;
}

var ViewContainer = React.createClass({
	statics: {
		shouldFillVerticalSpace: true
	},
	propTypes: {
		children: React.PropTypes.node
	},
	render () {
		var props = blacklist(this.props, 'children');
		return
{this.props.children}
;
	}
});

var ViewManager = React.createClass({
	statics: {
		shouldFillVerticalSpace: true
	},
	contextTypes: {
		app: React.PropTypes.object.isRequired
	},
	propTypes: {
		name: React.PropTypes.string,
		children: React.PropTypes.node,
		className: React.PropTypes.string,
		defaultView: React.PropTypes.string,
		onViewChange: React.PropTypes.func
	},
	getDefaultProps () {
		return {
			name: '__default'
		};
	},
	getInitialState () {
		return {
			views: createViewsFromChildren(this.props.children),
			currentView: this.props.defaultView,
			options: {}
		};
	},
	componentDidMount () {
		this.context.app.viewManagers[this.props.name] = this;
	},
	componentWillUnmount () {
		delete this.context.app.viewManagers[this.props.name];
	},
	componentWillReceiveProps (nextProps) {
		this.setState({
			views: createViewsFromChildren(this.props.children)
		});
		if (nextProps.name !== this.props.name) {
			this.context.app.viewManagers[nextProps.name] = this;
			delete this.context.app.viewManagers[this.props.name];
		}
		if (nextProps.currentView && nextProps.currentView !== this.state.currentView) {
			this.transitionTo(nextProps.currentView, { viewProps: nextProps.viewProps });
		}
	},
	transitionTo (viewKey, options) {
		if (typeof options === 'string') {
			options = { transition: options };
		}
		if (!options) options = {};
		this.activeTransitionOptions = options;
		this.context.app.viewManagerInTransition = this;
		this.props.onViewChange && this.props.onViewChange(viewKey);
		this.setState({
			currentView: viewKey,
			options: options
		}, () => {
			delete this.activeTransitionOptions;
			delete this.context.app.viewManagerInTransition;
		});
	},
	renderViewContainer () {
		var viewKey = this.state.currentView;
		if (!viewKey) {
			return (
				<ErrorView>
					ViewManager: {this.props.name}
					Error: There is no current View.
				</ErrorView>
			);
		}
		var view = this.state.views[viewKey];
		if (!view || !view.props.component) {
			return (
				<ErrorView>
					ViewManager: "{this.props.name}"
					The View "{viewKey}" is invalid.
				</ErrorView>
			);
		}
		var options = this.state.options || {};
		var viewClassName = classNames('View View--' + viewKey, view.props.className);
		var ViewComponent = view.props.component;
		var viewProps = blacklist(view.props, 'component', 'className');
		Object.assign(viewProps, options.viewProps);
		var viewElement = <ViewComponent {...viewProps} />;

		if (this.__lastRenderedView !== viewKey) {
			// console.log('initialising view ' + viewKey + ' with options', options);
			if (viewElement.type.navigationBar && viewElement.type.getNavigation) {
				var app = this.context.app;
				var transition = options.transition;
				if (app.viewManagerInTransition) {
					transition = app.viewManagerInTransition.activeTransitionOptions.transition;
				}
				setTimeout(() => {
					app.navigationBars[viewElement.type.navigationBar].updateWithTransition(viewElement.type.getNavigation(viewProps, app), transition);
				}, 0);
			}
			this.__lastRenderedView = viewKey;
		}

		return (
			<ViewContainer className={viewClassName} key={viewKey}>
				{viewElement}
			</ViewContainer>
		);
	},
	render () {
		var className = classNames('ViewManager', this.props.className);
		var viewContainer = this.renderViewContainer(this.state.currentView, { viewProps: this.state.currentViewProps });

		var transitionName = 'view-transition-instant';
		var transitionDurationEnter = 10;
		var transitionDurationLeave = 60;
		if (this.state.options.transition) {
			// console.log('applying view transition: ' + this.state.options.transition + ' to view ' + this.state.currentView);
			transitionName = 'view-transition-' + this.state.options.transition;
			if (this.state.options.transition === 'fade') {
				var transitionDurationEnter = 10;
				var transitionDurationLeave = 340;
			} else {
				var transitionDurationEnter = 500;
				var transitionDurationLeave = 500;
			}
		}
		return (
			<ReactCSSTransitionGroup transitionName={transitionName} transitionEnterTimeout={transitionDurationEnter} transitionLeaveTimeout={transitionDurationLeave} className={className} component="div">
				{viewContainer}
			</ReactCSSTransitionGroup>
		);
	}
});

export default ViewManager;
<commit_msg>Pass the nextProps to child Views so that they<commit_after>import blacklist from 'blacklist';
import classNames from 'classnames';
import ErrorView from './ErrorView';
import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';

function createViewsFromChildren (children) {
	var views = {};
	React.Children.forEach(children, function (view) {
		views[view.props.name] = view;
	});
	return views;
}

var ViewContainer = React.createClass({
	statics: {
		shouldFillVerticalSpace: true
	},
	propTypes: {
		children: React.PropTypes.node
	},
	render () {
		var props = blacklist(this.props, 'children');
		return
{this.props.children}
;
	}
});

var ViewManager = React.createClass({
	statics: {
		shouldFillVerticalSpace: true
	},
	contextTypes: {
		app: React.PropTypes.object.isRequired
	},
	propTypes: {
		name: React.PropTypes.string,
		children: React.PropTypes.node,
		className: React.PropTypes.string,
		defaultView: React.PropTypes.string,
		onViewChange: React.PropTypes.func
	},
	getDefaultProps () {
		return {
			name: '__default'
		};
	},
	getInitialState () {
		return {
			views: createViewsFromChildren(this.props.children),
			currentView: this.props.defaultView,
			options: {}
		};
	},
	componentDidMount () {
		this.context.app.viewManagers[this.props.name] = this;
	},
	componentWillUnmount () {
		delete this.context.app.viewManagers[this.props.name];
	},
	componentWillReceiveProps (nextProps) {
		this.setState({
			views: createViewsFromChildren(nextProps.children)
		});
		if (nextProps.name !== this.props.name) {
			this.context.app.viewManagers[nextProps.name] = this;
			delete this.context.app.viewManagers[this.props.name];
		}
		if (nextProps.currentView && nextProps.currentView !== this.state.currentView) {
			this.transitionTo(nextProps.currentView, { viewProps: nextProps.viewProps });
		}
	},
	transitionTo (viewKey, options) {
		if (typeof options === 'string') {
			options = { transition: options };
		}
		if (!options) options = {};
		this.activeTransitionOptions = options;
		this.context.app.viewManagerInTransition = this;
		this.props.onViewChange && this.props.onViewChange(viewKey);
		this.setState({
			currentView: viewKey,
			options: options
		}, () => {
			delete this.activeTransitionOptions;
			delete this.context.app.viewManagerInTransition;
		});
	},
	renderViewContainer () {
		var viewKey = this.state.currentView;
		if (!viewKey) {
			return (
				<ErrorView>
					ViewManager: {this.props.name}
					Error: There is no current View.
				</ErrorView>
			);
		}
		var view = this.state.views[viewKey];
		if (!view || !view.props.component) {
			return (
				<ErrorView>
					ViewManager: "{this.props.name}"
					The View "{viewKey}" is invalid.
				</ErrorView>
			);
		}
		var options = this.state.options || {};
		var viewClassName = classNames('View View--' + viewKey, view.props.className);
		var ViewComponent = view.props.component;
		var viewProps = blacklist(view.props, 'component', 'className');
		Object.assign(viewProps, options.viewProps);
		var viewElement = <ViewComponent {...viewProps} />;

		if (this.__lastRenderedView !== viewKey) {
			// console.log('initialising view ' + viewKey + ' with options', options);
			if (viewElement.type.navigationBar && viewElement.type.getNavigation) {
				var app = this.context.app;
				var transition = options.transition;
				if (app.viewManagerInTransition) {
					transition = app.viewManagerInTransition.activeTransitionOptions.transition;
				}
				setTimeout(() => {
					app.navigationBars[viewElement.type.navigationBar].updateWithTransition(viewElement.type.getNavigation(viewProps, app), transition);
				}, 0);
			}
			this.__lastRenderedView = viewKey;
		}

		return (
			<ViewContainer className={viewClassName} key={viewKey}>
				{viewElement}
			</ViewContainer>
		);
	},
	render () {
		var className = classNames('ViewManager', this.props.className);
		var viewContainer = this.renderViewContainer(this.state.currentView, { viewProps: this.state.currentViewProps });

		var transitionName = 'view-transition-instant';
		var transitionDurationEnter = 10;
		var transitionDurationLeave = 60;
		if (this.state.options.transition) {
			// console.log('applying view transition: ' + this.state.options.transition + ' to view ' + this.state.currentView);
			transitionName = 'view-transition-' + this.state.options.transition;
			if (this.state.options.transition === 'fade') {
				var transitionDurationEnter = 10;
				var transitionDurationLeave = 340;
			} else {
				var transitionDurationEnter = 500;
				var transitionDurationLeave = 500;
			}
		}
		return (
			<ReactCSSTransitionGroup transitionName={transitionName} transitionEnterTimeout={transitionDurationEnter} transitionLeaveTimeout={transitionDurationLeave} className={className} component="div">
				{viewContainer}
			</ReactCSSTransitionGroup>
		);
	}
});

export default ViewManager;
<|endoftext|>


<commit_before>const Command = require('../Command')

module.exports =
class NicknameGroupCommand extends Command {
  constructor (client) {
    super(client, {
      name: 'nicknamegroup',
      properName: 'NicknameGroup',
      aliases: ['rovernicknamegroup'],
      description: "`<groupid>` Set the Group RoVer will use when setting users' nicknames.",

      args: [
        {
          key: 'groupid',
          label: 'groupid',
          prompt: 'Nickname group',
          type: 'integer',
          infinite: false,
          default: 0
        }
      ]
    })
  }

  async fn (msg, args) {
    if (args.groupid) {
      this.server.setSetting('nicknameGroup', args.groupid)
      msg.reply(`Set nickname group to \`${args.groupid}\``)
    } else {
      this.server.setSetting('nicknameGroup', undefined)
      msg.reply('Nickname group has been removed.')
    }
  }
}
<commit_msg>Update NicknameGroupCommand.js<commit_after>const Command = require('../Command')

module.exports =
class NicknameGroupCommand extends Command {
  constructor (client) {
    super(client, {
      name: 'nicknamegroup',
      properName: 'NicknameGroup',
      aliases: ['rovernicknamegroup'],
      description: "`<groupid>` Set the Group RoVer will use when setting users' nicknames.",

      args: [
        {
          key: 'groupid',
          label: 'groupid',
          prompt: 'Nickname group',
          type: 'integer',
          infinite: false,
          default: 0
        }
      ]
    })
  }

  async fn (msg, args) {
    if (this.server.ongoingSettingsUpdate) return msg.reply('Server settings are currently being saved - please try again in a few moments.')
    if (args.groupid) {
      this.server.setSetting('nicknameGroup', args.groupid)
      msg.reply(`Set nickname group to \`${args.groupid}\``)
    } else {
      this.server.setSetting('nicknameGroup', undefined)
      msg.reply('Nickname group has been removed.')
    }
  }
}
<|endoftext|>


<commit_before>
var is_node_4_or_above = (+process.versions.node[0] >= 4);

module.exports = {
  info: {
    'csv': require('./valid.csv.info.json'),
    'geojson': require('./valid.geojson.info.json'),
    'gpx': require('./valid.gpx.info.json'),
    'kml': require('./valid.kml.info.json'),
    'shp': require('./valid.shp.info.json'),
    'tif': require('./valid.tif.info.json'),
    'tilejson': require('./valid.tilejson.info.json'),
    'tm2z': require('./valid.tm2z.info.json'),
    'serialtiles': require('./valid.serialtiles.info.json'),
    'serialtiles_png': require('./valid.serialtiles_png.info.json'),
    'serialtiles_pbf': require('./valid.serialtiles_pbf.info.json'),
    'mbtiles-carmen2': require('./valid.mbtiles.carmen2.info.json'),
    'mbtiles-onlygrids': require('./valid.mbtiles.onlygrids.info.json'),
    'mbtiles-onlytiles': require('./valid.mbtiles.onlytiles.info.json'),
    'mbtiles-tilesgrids': require('./valid.mbtiles.tilesgrid.info.json'),
    'mbtiles-update1': require('./valid.mbtiles.update1.info.json'),
    'mbtiles-update2': require('./valid.mbtiles.update2.info.json'),
    'mbtiles-vector': require('./valid.mbtiles.vector.info.json'),
    'mbtiles-vectorgzip': require('./valid.mbtiles.vectorgzip.info.json'),
    'mbtiles-webp': require('./valid.mbtiles.webp.info.json')
  },
  tm2zErrors: {
    'doublezip': 'Unknown filetype',
    'empty': 'project.xml not found in package',
    'filesize': 'Upload size should not exceed 750KB.',
    'gunzipsize': 'Unzipped size should not exceed 5MB.',
    'malformed': 'expected < at line 1',
    'missingfont': 'Failed to find font face \'This Is A Missing Font\' in style \'country_label\' in TextSymbolizer',
    'missingimage': 'file could not be found: \'invalid.tm2z-missing-image.tm2z/img/ice.jpg\' in style \'water\' in PolygonPatternSymbolizer',
    'nodirectory': is_node_4_or_above ? 'EISDIR: illegal operation on a directory, open \'invalid.tm2z-nodirectory.tm2z/\'' : 'EISDIR, open \'invalid.tm2z-nodirectory.tm2z/\'',
    'xmlsize': 'Unzipped project.xml size should not exceed 750KB.',
    'metadatasize': 'Metadata exceeds limit of 0.0k.',
    'maxdrawtime': 'At least one tile exceeds the draw time limit of 1ms. Please optimize your styles.',
    'avgdrawtime': 'The average tile draw time exceeds the limit of 1ms. Please optimize your styles.',
    'maximgbytes': 'At least one rendered tile exceeds the file size limit of 0.0k. Try lowering the number of PNG colors or JPEG quality in your project settings.',
    'avgimgbytes': 'The average rendered tile exceeds the file size limit of 0.0k. Try lowering the number of PNG colors or JPEG quality in your project settings.',
    'parsecolor': 'Invalid style',
    'filetoobig': 'File is larger than 1.02 kB. Too big to process.'
  },
  tilejsonErrors: {
    'metadatasize': 'Metadata exceeds limit of 0.0k.',
    'bounds': 'bounds must be an array of the form [west, south, east, north]',
    'hostname': 'Invalid hostname in TileJSON'
  },
  serialtilesErrors: {
    'tilesize': 'Tile exceeds maximum size of 1k at z1. Reduce the detail of data at this zoom level or omit it by adjusting your minzoom.',
    'noinfo': 'Missing Info object',
    'cantdeserialize': 'DeserializationError: Invalid data',
    'tiletype': 'Invalid tiletype',
    'gzipped': 'DeserializationError: Invalid data',
    'filetoobig': 'File is larger than 1.02 kB. Too big to process.'
  },
  omnivoreErrors: {
    'csvfilesize': 'File is larger than 1.02 kB. Too big to process.',
    'shpfilesize': 'File is larger than 1.02 kB. Too big to process.',
    'tiffilesize': 'File is larger than 1.02 kB. Too big to process.',
    'bad-projection': 'Error creating Mapnik Datasource: could not create file mapping for',
    'scrambled-files': 'Unknown filetype',
    'bad-bounds': 'bounds east value must be between -360 and 360',
    'bad-tif': 'Unknown filetype',
    'kmllayers': '16 layers found. Maximum of 15 layers allowed.'
  },
  mbtilesErrors: {
    'oldtemplate': 'Use TileMill 0.7 or later to export MBTiles with a valid template.',
    'notadb': 'Unknown filetype',
    'notiledata': 'SQLITE_ERROR: no such column: tile_data',
    'corrupt': '',
    'vector': 'Vector source must include "vector_layers" key',
    'oldcarmen': 'Carmen 0.1.x tilesets are no longer supported.',
    'empty': 'Tileset is empty.',
    'limits': 'Tileset exceeds processing limit.',
    'tiletoobig': 'Tile exceeds maximum size of 0k at z1. Reduce the detail of data at this zoom level or omit it by adjusting your minzoom.',
    'gridtoobig': 'Grid exceeds maximum size of 0k at z1. Reduce the detail of data at this zoom level or omit it by adjusting your minzoom.',
    'nulltile': 'SQLITE_ERROR: no such column: tile_data',
    'prepare': 'Source cannot contain prepare key',
    'filetoobig': 'File is larger than 1.02 kB. Too big to process.'
  },
  unsupportedErrors: 'Unknown filetype'
};
<commit_msg>revert nulltile message<commit_after>
var is_node_4_or_above = (+process.versions.node[0] >= 4);

module.exports = {
  info: {
    'csv': require('./valid.csv.info.json'),
    'geojson': require('./valid.geojson.info.json'),
    'gpx': require('./valid.gpx.info.json'),
    'kml': require('./valid.kml.info.json'),
    'shp': require('./valid.shp.info.json'),
    'tif': require('./valid.tif.info.json'),
    'tilejson': require('./valid.tilejson.info.json'),
    'tm2z': require('./valid.tm2z.info.json'),
    'serialtiles': require('./valid.serialtiles.info.json'),
    'serialtiles_png': require('./valid.serialtiles_png.info.json'),
    'serialtiles_pbf': require('./valid.serialtiles_pbf.info.json'),
    'mbtiles-carmen2': require('./valid.mbtiles.carmen2.info.json'),
    'mbtiles-onlygrids': require('./valid.mbtiles.onlygrids.info.json'),
    'mbtiles-onlytiles': require('./valid.mbtiles.onlytiles.info.json'),
    'mbtiles-tilesgrids': require('./valid.mbtiles.tilesgrid.info.json'),
    'mbtiles-update1': require('./valid.mbtiles.update1.info.json'),
    'mbtiles-update2': require('./valid.mbtiles.update2.info.json'),
    'mbtiles-vector': require('./valid.mbtiles.vector.info.json'),
    'mbtiles-vectorgzip': require('./valid.mbtiles.vectorgzip.info.json'),
    'mbtiles-webp': require('./valid.mbtiles.webp.info.json')
  },
  tm2zErrors: {
    'doublezip': 'Unknown filetype',
    'empty': 'project.xml not found in package',
    'filesize': 'Upload size should not exceed 750KB.',
    'gunzipsize': 'Unzipped size should not exceed 5MB.',
    'malformed': 'expected < at line 1',
    'missingfont': 'Failed to find font face \'This Is A Missing Font\' in style \'country_label\' in TextSymbolizer',
    'missingimage': 'file could not be found: \'invalid.tm2z-missing-image.tm2z/img/ice.jpg\' in style \'water\' in PolygonPatternSymbolizer',
    'nodirectory': is_node_4_or_above ? 'EISDIR: illegal operation on a directory, open \'invalid.tm2z-nodirectory.tm2z/\'' : 'EISDIR, open \'invalid.tm2z-nodirectory.tm2z/\'',
    'xmlsize': 'Unzipped project.xml size should not exceed 750KB.',
    'metadatasize': 'Metadata exceeds limit of 0.0k.',
    'maxdrawtime': 'At least one tile exceeds the draw time limit of 1ms. Please optimize your styles.',
    'avgdrawtime': 'The average tile draw time exceeds the limit of 1ms. Please optimize your styles.',
    'maximgbytes': 'At least one rendered tile exceeds the file size limit of 0.0k. Try lowering the number of PNG colors or JPEG quality in your project settings.',
    'avgimgbytes': 'The average rendered tile exceeds the file size limit of 0.0k. Try lowering the number of PNG colors or JPEG quality in your project settings.',
    'parsecolor': 'Invalid style',
    'filetoobig': 'File is larger than 1.02 kB. Too big to process.'
  },
  tilejsonErrors: {
    'metadatasize': 'Metadata exceeds limit of 0.0k.',
    'bounds': 'bounds must be an array of the form [west, south, east, north]',
    'hostname': 'Invalid hostname in TileJSON'
  },
  serialtilesErrors: {
    'tilesize': 'Tile exceeds maximum size of 1k at z1. Reduce the detail of data at this zoom level or omit it by adjusting your minzoom.',
    'noinfo': 'Missing Info object',
    'cantdeserialize': 'DeserializationError: Invalid data',
    'tiletype': 'Invalid tiletype',
    'gzipped': 'DeserializationError: Invalid data',
    'filetoobig': 'File is larger than 1.02 kB. Too big to process.'
  },
  omnivoreErrors: {
    'csvfilesize': 'File is larger than 1.02 kB. Too big to process.',
    'shpfilesize': 'File is larger than 1.02 kB. Too big to process.',
    'tiffilesize': 'File is larger than 1.02 kB. Too big to process.',
    'bad-projection': 'Error creating Mapnik Datasource: could not create file mapping for',
    'scrambled-files': 'Unknown filetype',
    'bad-bounds': 'bounds east value must be between -360 and 360',
    'bad-tif': 'Unknown filetype',
    'kmllayers': '16 layers found. Maximum of 15 layers allowed.'
  },
  mbtilesErrors: {
    'oldtemplate': 'Use TileMill 0.7 or later to export MBTiles with a valid template.',
    'notadb': 'Unknown filetype',
    'notiledata': 'SQLITE_ERROR: no such column: tile_data',
    'corrupt': '',
    'vector': 'Vector source must include "vector_layers" key',
    'oldcarmen': 'Carmen 0.1.x tilesets are no longer supported.',
    'empty': 'Tileset is empty.',
    'limits': 'Tileset exceeds processing limit.',
    'tiletoobig': 'Tile exceeds maximum size of 0k at z1. Reduce the detail of data at this zoom level or omit it by adjusting your minzoom.',
    'gridtoobig': 'Grid exceeds maximum size of 0k at z1. Reduce the detail of data at this zoom level or omit it by adjusting your minzoom.',
    'nulltile': 'Tile is invalid',
    'prepare': 'Source cannot contain prepare key',
    'filetoobig': 'File is larger than 1.02 kB. Too big to process.'
  },
  unsupportedErrors: 'Unknown filetype'
};
<|endoftext|>


<commit_before>var assert     = require('assert');
var specHelper = require('./specHelper');
var request    = specHelper.request;
var stringify  = function (o) { return JSON.stringify(o, null, ' '); };

describe('The features api', function () {
    beforeEach(function (done) {
        specHelper.db.resetAndSetup()
            .then(done.bind(null, null))
            .catch(done);
    });

    it('returns three feature toggles', function (done) {
        request
            .get('/features')
            .expect('Content-Type', /json/)
            .expect(200)
            .end(function (err, res) {
                assert(res.body.features.length === 3, "expected 3 features, got " + stringify(res.body));
                done();
            });
    });

    it('gets a feature by name', function (done) {
        request
            .get('/features/featureX')
            .expect('Content-Type', /json/)
            .expect(200, done);
    });

    it('creates new feature toggle', function (done) {
        request
            .post('/features')
            .send({name: 'com.test.feature', enabled: false})
            .set('Content-Type', 'application/json')
            .expect(201, done);
    });

    it('creates new feature toggle with createdBy', function (done) {
        request
            .post('/features')
            .send({name: 'com.test.Username', enabled: false})
            .set('Cookie', ['username=ivaosthu'])
            .set('Content-Type', 'application/json')
            .end(function(){
              request
                  .get('/events')
                  .end(function (err, res) {
                      assert.equal(res.body.events[0].createdBy, 'ivaosthu');
                      done();
                  });
            });
    });

    it('require new feature toggle to have a name', function (done) {
        request
            .post('/features')
            .send({name: ''})
            .set('Content-Type', 'application/json')
            .expect(400, done);
    });

    it('can not change status of feature toggle that does not exist', function (done) {
        request
            .put('/features/should-not-exist')
            .send({name: 'should-not-exist', enabled: false})
            .set('Content-Type', 'application/json')
            .expect(404, done);
    });

    it('can change status of feature toggle that does exist', function (done) {
        request
            .put('/features/featureY')
            .send({name: 'featureY', enabled: true})
            .set('Content-Type', 'application/json')
            .expect(200, done);
    });

    it('archives a feature by name', function (done) {
        request
            .delete('/features/featureX')
            .expect(200, done);
    });

    it('can not archive unknown feature', function (done) {
        request
            .delete('/features/featureUnknown')
            .expect(404, done);
    });

    it('refuses to create a feature with an existing name', function (done) {
        request
            .post('/features')
            .send({name: 'featureX'})
            .set('Content-Type', 'application/json')
            .expect(403, done);
    });

});
<commit_msg>Add test for asking for feature that dose not exist<commit_after>var assert     = require('assert');
var specHelper = require('./specHelper');
var request    = specHelper.request;
var stringify  = function (o) { return JSON.stringify(o, null, ' '); };

describe('The features api', function () {
    beforeEach(function (done) {
        specHelper.db.resetAndSetup()
            .then(done.bind(null, null))
            .catch(done);
    });

    it('returns three feature toggles', function (done) {
        request
            .get('/features')
            .expect('Content-Type', /json/)
            .expect(200)
            .end(function (err, res) {
                assert(res.body.features.length === 3, "expected 3 features, got " + stringify(res.body));
                done();
            });
    });

    it('gets a feature by name', function (done) {
        request
            .get('/features/featureX')
            .expect('Content-Type', /json/)
            .expect(200, done);
    });

    it('cant get feature that dose not exist', function (done) {
        request
            .get('/features/myFeature')
            .expect('Content-Type', /json/)
            .expect(404, done);
    });

    it('creates new feature toggle', function (done) {
        request
            .post('/features')
            .send({name: 'com.test.feature', enabled: false})
            .set('Content-Type', 'application/json')
            .expect(201, done);
    });

    it('creates new feature toggle with createdBy', function (done) {
        request
            .post('/features')
            .send({name: 'com.test.Username', enabled: false})
            .set('Cookie', ['username=ivaosthu'])
            .set('Content-Type', 'application/json')
            .end(function(){
              request
                  .get('/events')
                  .end(function (err, res) {
                      assert.equal(res.body.events[0].createdBy, 'ivaosthu');
                      done();
                  });
            });
    });

    it('require new feature toggle to have a name', function (done) {
        request
            .post('/features')
            .send({name: ''})
            .set('Content-Type', 'application/json')
            .expect(400, done);
    });

    it('can not change status of feature toggle that does not exist', function (done) {
        request
            .put('/features/should-not-exist')
            .send({name: 'should-not-exist', enabled: false})
            .set('Content-Type', 'application/json')
            .expect(404, done);
    });

    it('can change status of feature toggle that does exist', function (done) {
        request
            .put('/features/featureY')
            .send({name: 'featureY', enabled: true})
            .set('Content-Type', 'application/json')
            .expect(200, done);
    });

    it('archives a feature by name', function (done) {
        request
            .delete('/features/featureX')
            .expect(200, done);
    });

    it('can not archive unknown feature', function (done) {
        request
            .delete('/features/featureUnknown')
            .expect(404, done);
    });

    it('refuses to create a feature with an existing name', function (done) {
        request
            .post('/features')
            .send({name: 'featureX'})
            .set('Content-Type', 'application/json')
            .expect(403, done);
    });

});
<|endoftext|>


<commit_before>import { SELECTORS } from './Dropdown.utils'
import styled from '../../styled'
import Card from '../../Card'
import baseStyles from '../../../styles/resets/baseStyles.css.js'
import { getColor, rgba } from '../../../styles/utilities/color'

export const DropdownUI = styled('div')`
  ${baseStyles};
  position: relative;
`

export const MenuContainerUI = styled('div')`
  ${baseStyles};
  position: absolute;

  &.is-dropUp {
    bottom: 100%;
  }

  &.is-dropLeft {
    right: 0%;
  }

  .c-DropdownV2Block + .c-DropdownV2Block {
    border-top: 1px solid ${getColor('grey.600')};
  }
`

export const CardUI = styled(Card)`
  display: flex;
  flex-direction: column;
  min-height: 30px;
  min-width: 160px;
  max-height: 360px;
`

CardUI.defaultProps = {
  floating: true,
  seamless: true,
}

export const MenuWrapperUI = styled('div')`
  overflow-y: auto;
  overflow-x: hidden;
  max-height: 100%;
  min-height: 0;
  height: 100%;
  width: 100%;
`

export const MenuUI = styled('div')`
  ${baseStyles};
  padding: 8px 0;
  width: 100%;
`

MenuUI.defaultProps = {
  [SELECTORS.menuAttribute]: true,
  floating: true,
}

export const BlockUI = styled('div')`
  flex: none;
  padding: 8px 16px;
  min-height: 0;
  max-height: 100%;

  &.is-seamless {
    padding: 0;
  }

  &.is-stretchy {
    flex: 1;
  }
`

export const WrapperUI = styled('div')`
  ${baseStyles};
  visibility: hidden;
  pointer-events: none;
  position: relative;

  &:before {
    content: '';
    position: absolute;
    width: 15%;
    right: calc(100% - 20px);
    top: 34px;
    height: 50%;
  }
`

WrapperUI.defaultProps = {
  [SELECTORS.wrapperAttribute]: true,
}

export const ActionUI = styled('div')`
  ${baseStyles};
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;

  &.is-open {
    background-color: ${rgba(getColor('grey.300'), 1)};
    color: ${getColor('link.base')};

    ${MenuUI} {
      color: initial;
    }
  }

  &:active {
    background-color: ${rgba(getColor('grey.400'), 1)};
  }
`

ActionUI.defaultProps = {
  [SELECTORS.actionAttribute]: true,
}

export const ActionContentUI = styled('div')`
  flex: 1;
  min-width: 0;
  max-width: 100%;
`

export const ItemUI = styled('div')`
  ${baseStyles};
  background-color: ${rgba(getColor('grey.400'), 0)};
  border-radius: 0 !important;
  color: ${getColor('charcoal.400')};
  cursor: pointer;
  display: block;
  outline: none;
  position: static;
  text-decoration: none;
  transition: background-color 0.1s ease;
  user-select: none;

  &.is-option {
    padding: 8px 16px;
  }

  &.is-active {
    > ${ActionUI}, &.is-option {
      font-weight: 500;
    }
  }

  &.c-SelectionClearerItem + .c-DropdownV2Item {
    padding-top: 12px;
  }

  &:focus {
    ${MenuUI} {
      color: initial;
    }
  }

  &:hover {
    text-decoration: none;
  }

  &:last-child {
    border: none;
  }

  ${WrapperUI} {
    position: absolute;
    padding-left: 20px;
    padding-right: 20px;
    margin-left: -20px;
    margin-right: -20px;
  }

  &.is-focused {
    > ${ActionUI}, &.is-option {
      background-color: ${rgba(getColor('grey.300'), 1)};
      color: ${getColor('link.base')};
    }
  }
  &.is-focused:hover,
  &.is-open {
    > ${WrapperUI} {
      visibility: visible;
      pointer-events: auto;
    }
  }

  &.is-disabled {
    cursor: initial;
    pointer-events: none;
    opacity: 0.4;
  }
`

ItemUI.defaultProps = {
  [SELECTORS.itemAttribute]: true,
}

export const GroupUI = styled('div')`
  margin-top: 0;

  & + & {
    margin-top: 10px;
  }
`

export const HeaderUI = styled('div')`
  padding: 8px 16px;
`

export const DividerUI = styled('div')`
  background-color: ${getColor('grey.400')};
  margin: 8px 0;
  height: 1px;
`

export const TriggerUI = styled('span')`
  ${baseStyles};
  color: ${getColor('link.base')};
  cursor: pointer;
  display: inline-block;
  outline: none;

  &.is-disabled {
    color: ${getColor('charcoal.200')};
    pointer-events: none;
  }

  &.is-open {
    color: ${getColor('blue.700')};
  }

  & > * {
    pointer-events: none;
  }
`

TriggerUI.defaultProps = {
  [SELECTORS.triggerAttribute]: true,
  tabIndex: 0,
}

export const SubMenuIncidatorUI = styled('div')`
  pointer-events: none;
  margin-right: -8px;
  min-width: 0;
`

export const ItemSelectedCheckUI = styled('div')`
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 20px;

  &.is-selectionClearer-active {
    font-weight: bold;
  }
`

export const SelectedCheckmarkUI = styled('div')`
  width: 28px;
  padding-left: 4px;
  margin-left: auto;

  .c-Icon {
    right: -4px;
  }
`
<commit_msg>Fix dropdown active item color (#751)<commit_after>import { SELECTORS } from './Dropdown.utils'
import styled from '../../styled'
import Card from '../../Card'
import baseStyles from '../../../styles/resets/baseStyles.css.js'
import { getColor, rgba } from '../../../styles/utilities/color'

export const DropdownUI = styled('div')`
  ${baseStyles};
  position: relative;
`

export const MenuContainerUI = styled('div')`
  ${baseStyles};
  position: absolute;

  &.is-dropUp {
    bottom: 100%;
  }

  &.is-dropLeft {
    right: 0%;
  }

  .c-DropdownV2Block + .c-DropdownV2Block {
    border-top: 1px solid ${getColor('grey.600')};
  }
`

export const CardUI = styled(Card)`
  display: flex;
  flex-direction: column;
  min-height: 30px;
  min-width: 160px;
  max-height: 360px;
`

CardUI.defaultProps = {
  floating: true,
  seamless: true,
}

export const MenuWrapperUI = styled('div')`
  overflow-y: auto;
  overflow-x: hidden;
  max-height: 100%;
  min-height: 0;
  height: 100%;
  width: 100%;
`

export const MenuUI = styled('div')`
  ${baseStyles};
  padding: 8px 0;
  width: 100%;
`

MenuUI.defaultProps = {
  [SELECTORS.menuAttribute]: true,
  floating: true,
}

export const BlockUI = styled('div')`
  flex: none;
  padding: 8px 16px;
  min-height: 0;
  max-height: 100%;

  &.is-seamless {
    padding: 0;
  }

  &.is-stretchy {
    flex: 1;
  }
`

export const WrapperUI = styled('div')`
  ${baseStyles};
  visibility: hidden;
  pointer-events: none;
  position: relative;

  &:before {
    content: '';
    position: absolute;
    width: 15%;
    right: calc(100% - 20px);
    top: 34px;
    height: 50%;
  }
`

WrapperUI.defaultProps = {
  [SELECTORS.wrapperAttribute]: true,
}

export const ActionUI = styled('div')`
  ${baseStyles};
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;

  &.is-open {
    background-color: ${rgba(getColor('grey.300'), 1)};
    color: ${getColor('link.base')};

    ${MenuUI} {
      color: initial;
    }
  }

  &:active {
    background-color: ${rgba(getColor('grey.400'), 1)};
  }
`

ActionUI.defaultProps = {
  [SELECTORS.actionAttribute]: true,
}

export const ActionContentUI = styled('div')`
  flex: 1;
  min-width: 0;
  max-width: 100%;
`

export const ItemUI = styled('div')`
  ${baseStyles};
  background-color: ${rgba(getColor('grey.400'), 0)};
  border-radius: 0 !important;
  color: ${getColor('charcoal.400')};
  cursor: pointer;
  display: block;
  outline: none;
  position: static;
  text-decoration: none;
  transition: background-color 0.1s ease;
  user-select: none;

  &.is-option {
    padding: 8px 16px;
  }

  &.is-active {
    > ${ActionUI}, &.is-option {
      font-weight: 500;
      color: ${getColor('charcoal.600')};
    }
  }

  &.c-SelectionClearerItem + .c-DropdownV2Item {
    padding-top: 12px;
  }

  &:focus {
    ${MenuUI} {
      color: initial;
    }
  }

  &:hover {
    text-decoration: none;
  }

  &:last-child {
    border: none;
  }

  ${WrapperUI} {
    position: absolute;
    padding-left: 20px;
    padding-right: 20px;
    margin-left: -20px;
    margin-right: -20px;
  }

  &.is-focused {
    > ${ActionUI}, &.is-option {
      background-color: ${rgba(getColor('grey.300'), 1)};
      color: ${getColor('link.base')};
    }
  }
  &.is-focused:hover,
  &.is-open {
    > ${WrapperUI} {
      visibility: visible;
      pointer-events: auto;
    }
  }

  &.is-disabled {
    cursor: initial;
    pointer-events: none;
    opacity: 0.4;
  }
`

ItemUI.defaultProps = {
  [SELECTORS.itemAttribute]: true,
}

export const GroupUI = styled('div')`
  margin-top: 0;

  & + & {
    margin-top: 10px;
  }
`

export const HeaderUI = styled('div')`
  padding: 8px 16px;
`

export const DividerUI = styled('div')`
  background-color: ${getColor('grey.400')};
  margin: 8px 0;
  height: 1px;
`

export const TriggerUI = styled('span')`
  ${baseStyles};
  color: ${getColor('link.base')};
  cursor: pointer;
  display: inline-block;
  outline: none;

  &.is-disabled {
    color: ${getColor('charcoal.200')};
    pointer-events: none;
  }

  &.is-open {
    color: ${getColor('blue.700')};
  }

  & > * {
    pointer-events: none;
  }
`

TriggerUI.defaultProps = {
  [SELECTORS.triggerAttribute]: true,
  tabIndex: 0,
}

export const SubMenuIncidatorUI = styled('div')`
  pointer-events: none;
  margin-right: -8px;
  min-width: 0;
`

export const ItemSelectedCheckUI = styled('div')`
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 20px;

  &.is-selectionClearer-active {
    font-weight: bold;
  }
`

export const SelectedCheckmarkUI = styled('div')`
  width: 28px;
  padding-left: 4px;
  margin-left: auto;

  .c-Icon {
    right: -4px;
  }
`
<|endoftext|>


<commit_before>/**
 * Defines root namespace of Kekule.js.
 */

/**
 * @namespace
 * @description Root namespace of Kekule library.
 */
var Kekule = {
	LIBNAME: 'Kekule.js',
	LIBNAME_CORE: 'Kekule',
	VERSION: '0.9.6.21021000',
	/**
	 * A flag that indicate whether all essential Kekule modules are loaded into document.
	 * @ignore
	 */
	LOADED: false,
	/**
	 * An array of functions that need be called after load all Kekule modules.
	 * @private
	 */
	_afterLoadSysProcedures: [],
	/**
	 * An array of user functions that need be called after load all Kekule modules.
	 * @private
	 */
	_afterLoadUserProcedures: [],
	// Whether auto find title and description text for object property
	/** @ignore */
	PROP_AUTO_TITLE: true
};

/**
 * Called when all essential modules is loaded.
 * User should not call this function directly.
 * @private
 */
Kekule._loaded = function()
{
	if (Kekule.LOADED)
		return;
	Kekule.LOADED = true;
	var procs = Kekule._afterLoadSysProcedures;
	while (procs.length)
	{
		var proc = procs.shift();
		if (proc)
		{
			proc();
		}
	}

	var procs = Kekule._afterLoadUserProcedures;
	while (procs.length)
	{
		var proc = procs.shift();
		if (proc)
			proc();
	}

	// at last try fire a custom event
	var doc = Kekule.$jsRoot && Kekule.$jsRoot.document;
	if (doc && doc.createEvent && doc.body && doc.body.dispatchEvent)
	{
		var event = doc.createEvent('Event');
		event.initEvent('kekuleload', true, true);
		doc.body.dispatchEvent(event);
	}
};
/**
 * Return whether the whole lib is loaded.
 * @returns {boolean}
 * @private
 */
Kekule._isLoaded = function()
{
	return Kekule.LOADED;
};
/**
 * Register system procedure that need to be called after all modules are loaded.
 * User should not call this method directly.
 * @param {Func} proc
 * @private
 */
Kekule._registerAfterLoadSysProc = function(proc)
{
	if (proc)
	{
		if (Kekule.LOADED)
			proc();
		else
			Kekule._afterLoadSysProcedures.push(proc);
	}
};
/**
 * Register procedure that need to be called after all modules are loaded and all initial operations has been done.
 * @param {Func} proc
 * @private
 */
Kekule._ready = function(proc)
{
	if (proc)
	{
		if (Kekule.LOADED)
			proc();
		else
			Kekule._afterLoadUserProcedures.push(proc);
	}
};
Kekule._registerAfterLoadProc = Kekule._ready;  // for backward

/**
 * Root object of JavaScript environment, usually window.
 */
Kekule.$jsRoot = this;

if (typeof(self) === 'object')
	Kekule.$jsRoot = self;
else if (typeof(window) === 'object' && window && window.document)
	Kekule.$jsRoot = window;
else if (typeof(global) === 'object')  // node env
	Kekule.$jsRoot = global;

Kekule.$jsRoot.Kekule = Kekule;

/**
 * Root document of JavaScript environment.
 * Can be null in Node.js.
 */
Kekule.$document = (this && this.document) || null;

if (!Kekule.scriptSrcInfo)  // scriptSrcInfo maybe set already in node.js environment
{
	Kekule.scriptSrcInfo = Kekule.$jsRoot['__$kekule_load_info__'];
}
if (Kekule.scriptSrcInfo && Kekule.scriptSrcInfo.language)  // force Language
{
	Kekule.language = Kekule.scriptSrcInfo.language;
}
if (!Kekule.scriptSrcInfo && Kekule.$jsRoot.document)  // script info not found, may be use Kekule.min.js directly
{
	Kekule.scriptSrcInfo = (function (doc)
	{
		var matchResult;
		var scriptSrcPattern = /^(.*[\/\\])[^\/\\]*\.js(\?.*)?$/;
		var entranceSrc = /^(.*\/?)kekule\..*\.js(\?.*)?$/;
		var scriptSrc;
		if (doc && doc.currentScript && doc.currentScript.src)
		{
			scriptSrc = decodeURIComponent(doc.currentScript.src);  // sometimes the URL is escaped, ',' becomes '%2C'(e.g. in Moodle)
			if (scriptSrc)
			{
				matchResult = scriptSrc.match(scriptSrcPattern);
			}
		}
		else
		{
			var scriptElems = document.getElementsByTagName('script');
			var loc;
			for (var i = scriptElems.length - 1; i >= 0; --i)
			{
				var elem = scriptElems[i];
				scriptSrc = decodeURIComponent(elem.src);
				if (scriptSrc)
				{
					var matchResult = scriptSrc.match(entranceSrc);
					if (matchResult)
					{
						break;
					}
				}
			}
		}

		if (matchResult)
		{
			var pstr = matchResult[2];
			if (pstr)
				pstr = pstr.substr(1);  // eliminate starting '?'
			var result = {
				'src': scriptSrc,
				'path': matchResult[1],
				'paramStr': pstr,
				'useMinFile': true
			};
			return result;
		}

		return null;
	})(Kekule.$jsRoot.document);
}

if (!Kekule.scriptSrcInfo)
{
	Kekule.scriptSrcInfo = {useMinFile: true};
}

Kekule.environment = {
	scriptInfo: Kekule.scriptSrcInfo,
	isNode: !!((typeof process === 'object') && (typeof process.versions === 'object') && (typeof process.versions.node !== 'undefined')),
	isWeb: !!(typeof window === 'object' && window.document),
	variables: {},
	getEnvVar: function(key)
	{
		return Kekule.environment.variables[key];
	},
	setEnvVar: function(key, value)
	{
		Kekule.environment.variables[key] = value;
	}
};  // current runtime environment details

if (Kekule.scriptSrcInfo)
{
	Kekule.environment.nodeModule = Kekule.scriptSrcInfo.nodeModule;
	Kekule.environment.nodeRequire = Kekule.scriptSrcInfo.nodeRequire;
	Kekule.environment.setEnvVar('kekule.path', Kekule.scriptSrcInfo.path);
	Kekule.environment.setEnvVar('kekule.scriptSrc', Kekule.scriptSrcInfo.src);
	Kekule.environment.setEnvVar('kekule.useMinJs', Kekule.scriptSrcInfo.useMinFile);
	Kekule.environment.setEnvVar('kekule.language', Kekule.scriptSrcInfo.language);
}

if (Kekule.$jsRoot['__$kekule_scriptfile_utils__'])  // script file util methods
{
	Kekule._ScriptFileUtils_ = Kekule.$jsRoot['__$kekule_scriptfile_utils__'];
	Kekule.ScriptFileUtils = Kekule._ScriptFileUtils_;  // a default ScriptFileUtils impl, overrided by domUtils.js file
	Kekule.modules = function(modules, callback)   // util function to load additional modules in a existing Kekule environment, useful in node.js
	{
		var actualModules = [];
		if (typeof(modules) === 'string')  // a single string module param
			actualModules = [modules];
		else
			actualModules = modules;  // array param

		var scriptSrcInfo = Kekule.scriptSrcInfo;
		if (scriptSrcInfo)
		{
			var details = Kekule._ScriptFileUtils_.loadModuleScriptFiles(actualModules,
				Kekule.isUsingMinJs(), Kekule.getScriptPath(),
				scriptSrcInfo, function(error){
				if (callback)
					callback(error);
			});
			//console.log(details);
			return this;
		}
		else
			return this;
	};
	Kekule.loadModules = Kekule.modules;  // alias of function Kekule.modules
}

// add some util methods about Kekule.scriptSrcInfo
if (Kekule.scriptSrcInfo)
{
	Kekule.scriptSrcInfo.getValue = function(key)
	{
		return Kekule.scriptSrcInfo[key];
	};
	Kekule.scriptSrcInfo.setValue = function(key, value)
	{
		Kekule.scriptSrcInfo[key] = value;
	}
}

Kekule.getScriptPath = function()
{
	return Kekule.environment.getEnvVar('kekule.path') || Kekule.scriptSrcInfo.path;
};
Kekule.getScriptSrc = function()
{
	return Kekule.environment.getEnvVar('kekule.scriptSrc') || Kekule.scriptSrcInfo.src;
};
Kekule.isUsingMinJs = function()
{
	return Kekule.environment.getEnvVar('kekule.useMinJs') || Kekule.scriptSrcInfo.useMinFile;
};
Kekule.getLanguage = function()
{
	return Kekule.environment.getEnvVar('kekule.language') || Kekule.scriptSrcInfo.language;
};

Kekule._getStyleSheetBasePath = function()
{
	//var cssFileName = 'themes/default/kekule.css';
	var cssPath;
	//var scriptInfo = Kekule.scriptSrcInfo;
	//if (scriptInfo.useMinFile)
	if (Kekule.isUsingMinJs())
		cssPath = Kekule.getScriptPath(); // scriptInfo.path;
	else
		cssPath = Kekule.getScriptPath() + 'widgets/';  // scriptInfo.path + 'widgets/';
	return cssPath;
};
Kekule.getStyleSheetUrl = function()
{
	// TODO: current fixed to default theme
	var result = Kekule.environment.getEnvVar('kekule.themeUrl');
	if (!result)
	{
		var path = Kekule._getStyleSheetBasePath();
		result = path + 'themes/default/kekule.css';
	}
	return result;
};

if (Kekule.$jsRoot && Kekule.$jsRoot.addEventListener && Kekule.$jsRoot.postMessage)
{
	// response to special message, returns Kekule sys info.
	// This query is usually requested by browser addon to check
	// if Kekule lib is loaded into a web page
	Kekule.$jsRoot.addEventListener('message', function(event)
	{
		if (event.data === 'kekule-sys-info-query')
		{
			Kekule.$jsRoot.postMessage({
				'msg': 'kekule-sys-info-result',
				'libName': Kekule.LIBNAME,
				'version': Kekule.VERSION
				//'scriptSrcInfo': Kekule.scriptSrcInfo
			}, '*');
		}
	}, false);
}

/**
 * A namespace for development tools.
 * @namespace
 */
Kekule.Dev = {};

// Also store Class/ClassEx/ObjectEx/DataType in Kekule namespace
/** @ignore */
Kekule.Class = Class;
Kekule.ClassEx = ClassEx;
Kekule.ObjectEx = ObjectEx;
Kekule.DataType = DataType;<commit_msg>Stores window variable in Kekule.window field<commit_after>/**
 * Defines root namespace of Kekule.js.
 */

/**
 * @namespace
 * @description Root namespace of Kekule library.
 */
var Kekule = {
	LIBNAME: 'Kekule.js',
	LIBNAME_CORE: 'Kekule',
	VERSION: '0.9.6.21021000',
	/**
	 * A flag that indicate whether all essential Kekule modules are loaded into document.
	 * @ignore
	 */
	LOADED: false,
	/**
	 * An array of functions that need be called after load all Kekule modules.
	 * @private
	 */
	_afterLoadSysProcedures: [],
	/**
	 * An array of user functions that need be called after load all Kekule modules.
	 * @private
	 */
	_afterLoadUserProcedures: [],
	// Whether auto find title and description text for object property
	/** @ignore */
	PROP_AUTO_TITLE: true
};

/**
 * Called when all essential modules is loaded.
 * User should not call this function directly.
 * @private
 */
Kekule._loaded = function()
{
	if (Kekule.LOADED)
		return;
	Kekule.LOADED = true;
	var procs = Kekule._afterLoadSysProcedures;
	while (procs.length)
	{
		var proc = procs.shift();
		if (proc)
		{
			proc();
		}
	}

	var procs = Kekule._afterLoadUserProcedures;
	while (procs.length)
	{
		var proc = procs.shift();
		if (proc)
			proc();
	}

	// at last try fire a custom event
	var doc = Kekule.$jsRoot && Kekule.$jsRoot.document;
	if (doc && doc.createEvent && doc.body && doc.body.dispatchEvent)
	{
		var event = doc.createEvent('Event');
		event.initEvent('kekuleload', true, true);
		doc.body.dispatchEvent(event);
	}
};
/**
 * Return whether the whole lib is loaded.
 * @returns {boolean}
 * @private
 */
Kekule._isLoaded = function()
{
	return Kekule.LOADED;
};
/**
 * Register system procedure that need to be called after all modules are loaded.
 * User should not call this method directly.
 * @param {Func} proc
 * @private
 */
Kekule._registerAfterLoadSysProc = function(proc)
{
	if (proc)
	{
		if (Kekule.LOADED)
			proc();
		else
			Kekule._afterLoadSysProcedures.push(proc);
	}
};
/**
 * Register procedure that need to be called after all modules are loaded and all initial operations has been done.
 * @param {Func} proc
 * @private
 */
Kekule._ready = function(proc)
{
	if (proc)
	{
		if (Kekule.LOADED)
			proc();
		else
			Kekule._afterLoadUserProcedures.push(proc);
	}
};
Kekule._registerAfterLoadProc = Kekule._ready;  // for backward

/**
 * Root object of JavaScript environment, usually window.
 */
Kekule.$jsRoot = this;

if (typeof(self) === 'object')
	Kekule.$jsRoot = self;
else if (typeof(window) === 'object' && window && window.document)
{
	Kekule.$jsRoot = window;
	Kekule.window = window;
}
else if (typeof(global) === 'object')  // node env
	Kekule.$jsRoot = global;

Kekule.$jsRoot.Kekule = Kekule;

/**
 * Root document of JavaScript environment.
 * Can be null in Node.js.
 */
Kekule.$document = (this && this.document) || null;

if (!Kekule.scriptSrcInfo)  // scriptSrcInfo maybe set already in node.js environment
{
	Kekule.scriptSrcInfo = Kekule.$jsRoot['__$kekule_load_info__'];
}
if (Kekule.scriptSrcInfo && Kekule.scriptSrcInfo.language)  // force Language
{
	Kekule.language = Kekule.scriptSrcInfo.language;
}
if (!Kekule.scriptSrcInfo && Kekule.$jsRoot.document)  // script info not found, may be use Kekule.min.js directly
{
	Kekule.scriptSrcInfo = (function (doc)
	{
		var matchResult;
		var scriptSrcPattern = /^(.*[\/\\])[^\/\\]*\.js(\?.*)?$/;
		var entranceSrc = /^(.*\/?)kekule\..*\.js(\?.*)?$/;
		var scriptSrc;
		if (doc && doc.currentScript && doc.currentScript.src)
		{
			scriptSrc = decodeURIComponent(doc.currentScript.src);  // sometimes the URL is escaped, ',' becomes '%2C'(e.g. in Moodle)
			if (scriptSrc)
			{
				matchResult = scriptSrc.match(scriptSrcPattern);
			}
		}
		else
		{
			var scriptElems = document.getElementsByTagName('script');
			var loc;
			for (var i = scriptElems.length - 1; i >= 0; --i)
			{
				var elem = scriptElems[i];
				scriptSrc = decodeURIComponent(elem.src);
				if (scriptSrc)
				{
					var matchResult = scriptSrc.match(entranceSrc);
					if (matchResult)
					{
						break;
					}
				}
			}
		}

		if (matchResult)
		{
			var pstr = matchResult[2];
			if (pstr)
				pstr = pstr.substr(1);  // eliminate starting '?'
			var result = {
				'src': scriptSrc,
				'path': matchResult[1],
				'paramStr': pstr,
				'useMinFile': true
			};
			return result;
		}

		return null;
	})(Kekule.$jsRoot.document);
}

if (!Kekule.scriptSrcInfo)
{
	Kekule.scriptSrcInfo = {useMinFile: true};
}

Kekule.environment = {
	scriptInfo: Kekule.scriptSrcInfo,
	isNode: !!((typeof process === 'object') && (typeof process.versions === 'object') && (typeof process.versions.node !== 'undefined')),
	isWeb: !!(typeof window === 'object' && window.document),
	variables: {},
	getEnvVar: function(key)
	{
		return Kekule.environment.variables[key];
	},
	setEnvVar: function(key, value)
	{
		Kekule.environment.variables[key] = value;
	}
};  // current runtime environment details

if (Kekule.scriptSrcInfo)
{
	Kekule.environment.nodeModule = Kekule.scriptSrcInfo.nodeModule;
	Kekule.environment.nodeRequire = Kekule.scriptSrcInfo.nodeRequire;
	Kekule.environment.setEnvVar('kekule.path', Kekule.scriptSrcInfo.path);
	Kekule.environment.setEnvVar('kekule.scriptSrc', Kekule.scriptSrcInfo.src);
	Kekule.environment.setEnvVar('kekule.useMinJs', Kekule.scriptSrcInfo.useMinFile);
	Kekule.environment.setEnvVar('kekule.language', Kekule.scriptSrcInfo.language);
}

if (Kekule.$jsRoot['__$kekule_scriptfile_utils__'])  // script file util methods
{
	Kekule._ScriptFileUtils_ = Kekule.$jsRoot['__$kekule_scriptfile_utils__'];
	Kekule.ScriptFileUtils = Kekule._ScriptFileUtils_;  // a default ScriptFileUtils impl, overrided by domUtils.js file
	Kekule.modules = function(modules, callback)   // util function to load additional modules in a existing Kekule environment, useful in node.js
	{
		var actualModules = [];
		if (typeof(modules) === 'string')  // a single string module param
			actualModules = [modules];
		else
			actualModules = modules;  // array param

		var scriptSrcInfo = Kekule.scriptSrcInfo;
		if (scriptSrcInfo)
		{
			var details = Kekule._ScriptFileUtils_.loadModuleScriptFiles(actualModules,
				Kekule.isUsingMinJs(), Kekule.getScriptPath(),
				scriptSrcInfo, function(error){
				if (callback)
					callback(error);
			});
			//console.log(details);
			return this;
		}
		else
			return this;
	};
	Kekule.loadModules = Kekule.modules;  // alias of function Kekule.modules
}

// add some util methods about Kekule.scriptSrcInfo
if (Kekule.scriptSrcInfo)
{
	Kekule.scriptSrcInfo.getValue = function(key)
	{
		return Kekule.scriptSrcInfo[key];
	};
	Kekule.scriptSrcInfo.setValue = function(key, value)
	{
		Kekule.scriptSrcInfo[key] = value;
	}
}

Kekule.getScriptPath = function()
{
	return Kekule.environment.getEnvVar('kekule.path') || Kekule.scriptSrcInfo.path;
};
Kekule.getScriptSrc = function()
{
	return Kekule.environment.getEnvVar('kekule.scriptSrc') || Kekule.scriptSrcInfo.src;
};
Kekule.isUsingMinJs = function()
{
	return Kekule.environment.getEnvVar('kekule.useMinJs') || Kekule.scriptSrcInfo.useMinFile;
};
Kekule.getLanguage = function()
{
	return Kekule.environment.getEnvVar('kekule.language') || Kekule.scriptSrcInfo.language;
};

Kekule._getStyleSheetBasePath = function()
{
	//var cssFileName = 'themes/default/kekule.css';
	var cssPath;
	//var scriptInfo = Kekule.scriptSrcInfo;
	//if (scriptInfo.useMinFile)
	if (Kekule.isUsingMinJs())
		cssPath = Kekule.getScriptPath(); // scriptInfo.path;
	else
		cssPath = Kekule.getScriptPath() + 'widgets/';  // scriptInfo.path + 'widgets/';
	return cssPath;
};
Kekule.getStyleSheetUrl = function()
{
	// TODO: current fixed to default theme
	var result = Kekule.environment.getEnvVar('kekule.themeUrl');
	if (!result)
	{
		var path = Kekule._getStyleSheetBasePath();
		result = path + 'themes/default/kekule.css';
	}
	return result;
};

if (Kekule.$jsRoot && Kekule.$jsRoot.addEventListener && Kekule.$jsRoot.postMessage)
{
	// response to special message, returns Kekule sys info.
	// This query is usually requested by browser addon to check
	// if Kekule lib is loaded into a web page
	Kekule.$jsRoot.addEventListener('message', function(event)
	{
		if (event.data === 'kekule-sys-info-query')
		{
			Kekule.$jsRoot.postMessage({
				'msg': 'kekule-sys-info-result',
				'libName': Kekule.LIBNAME,
				'version': Kekule.VERSION
				//'scriptSrcInfo': Kekule.scriptSrcInfo
			}, '*');
		}
	}, false);
}

/**
 * A namespace for development tools.
 * @namespace
 */
Kekule.Dev = {};

// Also store Class/ClassEx/ObjectEx/DataType in Kekule namespace
/** @ignore */
Kekule.Class = Class;
Kekule.ClassEx = ClassEx;
Kekule.ObjectEx = ObjectEx;
Kekule.DataType = DataType;<|endoftext|>


<commit_before>Utils.extend( KityMinder, {
    _protocals: {},
    registerProtocal: function ( name, protocalDeal ) {
        KityMinder._protocals[ name ] = protocalDeal();
    },
    findProtocal: function ( name ) {
        return KityMinder._protocals[ name ] || null;
    },
    getSupportedProtocals: function () {
        return Utils.keys( KityMinder._protocals ).sort( function ( a, b ) {
            return KityMinder._protocals[ b ].recognizePriority - KityMinder._protocals[ a ].recognizePriority;
        } );
    },
    getAllRegisteredProtocals: function () {
        return KityMinder._protocals;
    }
} );

// 这里的 Json 是一个对象
function exportNode( node ) {
    var exported = {};
    exported.data = node.getData();
    var childNodes = node.getChildren();
    if ( childNodes.length ) {
        exported.children = [];
        for ( var i = 0; i < childNodes.length; i++ ) {
            exported.children.push( exportNode( childNodes[ i ] ) );
        }
    }
    return exported;
}

var DEFAULT_TEXT = {
    'root': 'maintopic',
    'main': 'topic'
};

function importNode( node, json, km ) {
    var data = json.data;
    for ( var field in data ) {
        node.setData( field, data[ field ] );
    }
    node.setText( data.text || km.getLang( DEFAULT_TEXT[ data.type ] ) );

    var childrenTreeData = json.children;
    if ( !childrenTreeData ) return;
    for ( var i = 0; i < childrenTreeData.length; i++ ) {
        var childNode = new MinderNode();
        importNode( childNode, childrenTreeData[ i ], km );
        node.appendChild( childNode );
    }
    return node;
}

// 导入导出
kity.extendClass( Minder, {
    exportData: function ( protocalName ) {
        var json, protocal;

        json = exportNode( this.getRoot() );
        protocal = KityMinder.findProtocal( protocalName );
        if ( protocal ) {
            return protocal.encode( json, this );
        } else {
            return json;
        }
    },

    importData: function ( local, protocalName ) {
        var json, protocal;

        if ( protocalName ) {
            protocal = KityMinder.findProtocal( protocalName );
        } else {
            KityMinder.getSupportedProtocals().every( function ( name ) {
                var test = KityMinder.findProtocal( name );
                if ( test.recognize && test.recognize( local ) ) {
                    protocal = test;
                }
                return !protocal;
            } );
        }

        if ( !protocal ) {
            throw new Error( "Unsupported protocal: " + protocalName );
        }

        var params = {
            local: local,
            protocalName: protocalName,
            protocal: protocal
        };

        // 是否需要阻止导入
        var stoped = this._fire( new MinderEvent( 'beforeimport', params, true ) );
        if ( stoped ) return this;

        json = params.json || ( params.json = protocal.decode( local ) );

        this._fire( new MinderEvent( 'preimport', params, false ) );

        // 删除当前所有节点
        while ( this._root.getChildren().length ) {
            this._root.removeChild( 0 );
        }

        importNode( this._root, json, this );

        this._fire( new MinderEvent( 'import', params, false ) );
        this._firePharse( {
            type: 'contentchange'
        } );
        this._firePharse( {
            type: 'interactchange'
        } );

        return this;
    }
} );<commit_msg>fixed style<commit_after>Utils.extend( KityMinder, {
    _protocals: {},
    registerProtocal: function ( name, protocalDeal ) {
        KityMinder._protocals[ name ] = protocalDeal();
    },
    findProtocal: function ( name ) {
        return KityMinder._protocals[ name ] || null;
    },
    getSupportedProtocals: function () {
        return Utils.keys( KityMinder._protocals ).sort( function ( a, b ) {
            return KityMinder._protocals[ b ].recognizePriority - KityMinder._protocals[ a ].recognizePriority;
        } );
    },
    getAllRegisteredProtocals: function () {
        return KityMinder._protocals;
    }
} );

// 这里的 Json 是一个对象
function exportNode( node ) {
    var exported = {};
    exported.data = node.getData();
    var childNodes = node.getChildren();
    if ( childNodes.length ) {
        exported.children = [];
        for ( var i = 0; i < childNodes.length; i++ ) {
            exported.children.push( exportNode( childNodes[ i ] ) );
        }
    }
    return exported;
}

var DEFAULT_TEXT = {
    'root': 'maintopic',
    'main': 'topic'
};

function importNode( node, json, km ) {
    var data = json.data;
    for ( var field in data ) {
        node.setData( field, data[ field ] );
    }
    node.setText( data.text || km.getLang( DEFAULT_TEXT[ data.type ] ) );

    var childrenTreeData = json.children;
    if ( !childrenTreeData ) return;
    for ( var i = 0; i < childrenTreeData.length; i++ ) {
        var childNode = new MinderNode();
        importNode( childNode, childrenTreeData[ i ], km );
        node.appendChild( childNode );
    }
    return node;
}

// 导入导出
kity.extendClass( Minder, {
    exportData: function ( protocalName ) {
        var json, protocal;

        json = exportNode( this.getRoot() );
        protocal = KityMinder.findProtocal( protocalName );
        if ( protocal ) {
            return protocal.encode( json, this );
        } else {
            return json;
        }
    },

    importData: function ( local, protocalName ) {
        var json, protocal;

        if ( protocalName ) {
            protocal = KityMinder.findProtocal( protocalName );
        } else {
            KityMinder.getSupportedProtocals().every( function ( name ) {
                var test = KityMinder.findProtocal( name );
                if ( test.recognize && test.recognize( local ) ) {
                    protocal = test;
                }
                return !protocal;
            } );
        }

        if ( !protocal ) {
            throw new Error( "Unsupported protocal: " + protocalName );
        }

        var params = {
            local: local,
            protocalName: protocalName,
            protocal: protocal
        };

        // 是否需要阻止导入
        var stoped = this._fire( new MinderEvent( 'beforeimport', params, true ) );
        if ( stoped ) return this;

        json = params.json || ( params.json = protocal.decode( local ) );

        this._fire( new MinderEvent( 'preimport', params, false ) );

        // 删除当前所有节点
        while ( this._root.getChildren().length ) {
            this._root.removeChild( 0 );
        }
        var curLayout = this._root.getData( "currentstyle" );
        this._root.setData();
        this._root.setData( "currentstyle", curLayout );
        importNode( this._root, json, this );

        this._fire( new MinderEvent( 'import', params, false ) );
        this._firePharse( {
            type: 'contentchange'
        } );
        this._firePharse( {
            type: 'interactchange'
        } );

        return this;
    }
} );<|endoftext|>


<commit_before>import cx from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
import { DropTarget } from 'react-dnd';
import ActiveIcon from 'material-ui/svg-icons/navigation/check';
import { MEDIA } from '../../../constants/DDItemTypes';
import Loader from '../../Loader';

const playlistTarget = {
  drop({ playlist, onAddToPlaylist }, monitor) {
    const { media } = monitor.getItem();
    onAddToPlaylist(playlist, media);
  },
};

const collect = (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver(),
});

const enhance = DropTarget(MEDIA, playlistTarget, collect);

class PlaylistRow extends React.Component {
  static propTypes = {
    className: PropTypes.string,
    playlist: PropTypes.object,
    selected: PropTypes.bool,
    isOver: PropTypes.bool.isRequired,

    connectDropTarget: PropTypes.func.isRequired,
    onClick: PropTypes.func,
    // Used in the drop handler above 👆
    // eslint-disable-next-line react/no-unused-prop-types
    onAddToPlaylist: PropTypes.func,
  };

  render() {
    const {
      className,
      playlist,
      selected,

      onClick,

      connectDropTarget,
      isOver,
    } = this.props;
    const activeClass = playlist.active && 'is-active';
    const selectedClass = selected && 'is-selected';
    const droppableClass = isOver && 'is-droppable';

    let icon;
    if (playlist.creating) {
      icon = (

          <Loader size="tiny" />

      );
    } else if (playlist.active) {
      icon = (

          <ActiveIcon color="#fff" />

      );
    }

    return connectDropTarget((
      <button
        role="menuitem"
        className={cx('PlaylistMenuRow', activeClass, selectedClass, droppableClass, className)}
        onClick={onClick}
      >

            {icon}
            {playlist.name}

{playlist.size}

      </button>
    ));
  }
}

export default enhance(PlaylistRow);
<commit_msg>Port PlaylistMenuRow to material-ui@next.<commit_after>import cx from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
import { DropTarget } from 'react-dnd';
import ActiveIcon from 'material-ui-icons/Check';
import { MEDIA } from '../../../constants/DDItemTypes';
import Loader from '../../Loader';

const playlistTarget = {
  drop({ playlist, onAddToPlaylist }, monitor) {
    const { media } = monitor.getItem();
    onAddToPlaylist(playlist, media);
  },
};

const collect = (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver(),
});

const enhance = DropTarget(MEDIA, playlistTarget, collect);

class PlaylistRow extends React.Component {
  static propTypes = {
    className: PropTypes.string,
    playlist: PropTypes.object,
    selected: PropTypes.bool,
    isOver: PropTypes.bool.isRequired,

    connectDropTarget: PropTypes.func.isRequired,
    onClick: PropTypes.func,
    // Used in the drop handler above 👆
    // eslint-disable-next-line react/no-unused-prop-types
    onAddToPlaylist: PropTypes.func,
  };

  render() {
    const {
      className,
      playlist,
      selected,

      onClick,

      connectDropTarget,
      isOver,
    } = this.props;
    const activeClass = playlist.active && 'is-active';
    const selectedClass = selected && 'is-selected';
    const droppableClass = isOver && 'is-droppable';

    let icon;
    if (playlist.creating) {
      icon = (

          <Loader size="tiny" />

      );
    } else if (playlist.active) {
      icon = (

          <ActiveIcon />

      );
    }

    return connectDropTarget((
      <button
        role="menuitem"
        className={cx('PlaylistMenuRow', activeClass, selectedClass, droppableClass, className)}
        onClick={onClick}
      >

            {icon}
            {playlist.name}

{playlist.size}

      </button>
    ));
  }
}

export default enhance(PlaylistRow);
<|endoftext|>


<commit_before>// Mocha configuration
(function() {
  'use strict';

  if (host.browser) {
    mocha.setup('bdd');
    mocha.fullTrace();
    mocha.asyncOnly();
    mocha.checkLeaks();
    mocha.globals(['$0', '$1', '$2', '$3', '$4', '$5']);

    // Output each test's name, for debugging purposes
    beforeEach(function() {
      console.log('START ' + this.currentTest.parent.title + ' - ' + this.currentTest.title);
    });
    afterEach(function() {
      console.log('DONE  ' + this.currentTest.parent.title + ' - ' + this.currentTest.title);
    });
  }

  beforeEach(function() {
    // Flag TravisCI and SauceLabs as being very slow environments
    var isSlowEnvironment = host.env.TRAVIS || host.karma;

    // Most of our tests perform multiple AJAX requests,
    // so we need to increase the timeouts to allow for that
    this.currentTest.timeout(isSlowEnvironment ? 10000 : 4000);
    this.currentTest.slow(1000);
  });

})();
<commit_msg>ESlint fixes<commit_after>// Mocha configuration
(function () {
  'use strict';

  if (host.browser) {
    mocha.setup('bdd');
    mocha.fullTrace();
    mocha.asyncOnly();
    mocha.checkLeaks();
    mocha.globals(['$0', '$1', '$2', '$3', '$4', '$5']);

    // Output each test's name, for debugging purposes
    beforeEach(function () {
      console.log('START ' + this.currentTest.parent.title + ' - ' + this.currentTest.title);
    });
    afterEach(function () {
      console.log('DONE  ' + this.currentTest.parent.title + ' - ' + this.currentTest.title);
    });
  }

  beforeEach(function () {
    // Flag TravisCI and SauceLabs as being very slow environments
    var isSlowEnvironment = host.env.TRAVIS || host.karma;

    // Most of our tests perform multiple AJAX requests,
    // so we need to increase the timeouts to allow for that
    this.currentTest.timeout(isSlowEnvironment ? 10000 : 4000);
    this.currentTest.slow(1000);
  });

}());
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const paths = exports;

paths.root = path.resolve('test', 'test-app');
paths.lib = path.join(paths.root, 'lib');
paths.dist = path.join(paths.root, 'dist');
paths.entryFile = path.join(paths.lib, 'index.js');
paths.bundleFile = path.join(paths.dist, 'bundle.js');
paths.mapFile = path.join(paths.dist, 'bundle.js.map');
<commit_msg>fixed a failing test due to NPM 2.0 installation directory<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const paths = exports;

paths.root = path.resolve('test', 'test-app');
paths.lib = path.join(paths.root, 'lib');
paths.dist = path.join(paths.root, 'dist');
paths.entryFile = path.join(paths.lib, 'index.js');
paths.bundleFile = path.join(paths.dist, 'bundle.js');
paths.mapFile = path.join(paths.dist, 'bundle.js.map');

if (fs.existsSync('node_modules/browser-pack')) {
  // NPM 3.0 installs all dependencies directly under "node_modules"
  paths.prelude = 'node_modules/browser-pack/_prelude.js';
}
else {
  // NPM 2.0 installs dependencies under their parent module
  paths.prelude = 'node_modules/browserify/node_modules/browser-pack/_prelude.js';
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

var basic_test = require('./basic-tester.js');

basic_test.BASIC_TEST('Functions', 'Classic', `
DEF FNdist(x, y) = SQR(x^2 + y^2)
a = 3
b = 4
PRINT FNdist(a, b)
`, `
5
`);

basic_test.BASIC_TEST('Functions', 'NewStyle', `
FUNCTION Dist(x, y)
  Dist = SQR(x^2 + y^2)
END FUNCTION
a = 3
b = 4
PRINT Dist(a, b)
`, `
5
`);

basic_test.BASIC_TEST('Functions', 'CallLayers', `
FUNCTION Inc(x)
  Inc = x + 1
END FUNCTION
PRINT Inc(Inc(Inc(Inc(3))))
`, `
7
`);

basic_test.BASIC_TEST('Functions', 'DefLayers', `
FUNCTION Baz(x)
  Baz = x * 2
END FUNCTION

FUNCTION Bar(x)
  Bar = Baz(x) * 3
END FUNCTION

FUNCTION Foo(x)
  Foo = Bar(x) * 5
END FUNCTION

a = 1
PRINT Foo(a)
`, `
30
`);

basic_test.BASIC_TEST('Functions', 'RecursiveImplicit', `
FUNCTION Factorial(n)
  IF n = 0 OR n = 1 THEN
    Factorial = 1
  ELSE
    Factorial = n * Factorial(n - 1)
  END IF
END FUNCTION

a = 4
PRINT Factorial(a)
`, `
24
`);

basic_test.BASIC_TEST('Functions', 'RecursiveExplicit', `
FUNCTION Factorial(n AS INTEGER) AS INTEGER
  IF n = 0 OR n = 1 THEN
    Factorial = 1
  ELSE
    Factorial = n * Factorial(n - 1)
  END IF
END FUNCTION

a = 4
PRINT Factorial(a)
`, `
24
`);

basic_test.BASIC_TEST('Functions', 'RecursiveExplicitWithLocal', `
FUNCTION Factorial(n AS INTEGER) AS INTEGER
  IF n = 0 OR n = 1 THEN
    Factorial = 1
  ELSE
    temp = n * Factorial(n - 1)
    Factorial = temp
  END IF
END FUNCTION

a = 4
PRINT Factorial(a)
`, `
24
`);

basic_test.BASIC_TEST('Functions', 'Predeclare', `
DECLARE FUNCTION Adder(x AS INTEGER, y AS INTEGER) AS INTEGER
PRINT Adder(1, 2)
FUNCTION Adder(x AS INTEGER, y AS INTEGER) AS INTEGER
  Adder = x + y
END FUNCTION
`, `
3
`);

basic_test.BASIC_TEST('Functions', 'ByRef', `
FUNCTION Changer(x as INTEGER)
  x = 2
  Changer = 3
END FUNCTION
a = 1
PRINT Changer(a)
PRINT a
`, `
3
2
`);

basic_test.BASIC_TEST('Functions', 'Multi', `
FUNCTION Plus1(x as INTEGER)
  Plus1 = x + 1
END FUNCTION
PRINT Plus1(3) + Plus1(4) + Plus1(6)
`, `
16
`);

basic_test.BASIC_TEST('Functions', 'TreeSize', `
FUNCTION TreeSize(n)
  IF n = 1 THEN
    TreeSize = 1
  ELSE
    TreeSize = TreeSize(n - 1) + TreeSize(n - 1) + 1
  END IF
END FUNCTION
PRINT TreeSize(5)
`, `
31
`);

basic_test.BASIC_TEST('Subroutines', 'Depth', `
a = stackdepth()
b = basedepth()

FUNCTION Foo(a$)
  b$ = a$
  print "Foo sp: "; stackdepth() - a
  print "Foo bp: "; basedepth() - b
  Foo = 1
END FUNCTION

FUNCTION Bar()
  print "Bar sp: "; stackdepth() - a
  print "Bar bp: "; basedepth() - b
  Bar = Foo("hi")
  print "Bar sp: "; stackdepth() - a
  print "Bar bp: "; basedepth() - b
END FUNCTION

print "Root sp: "; stackdepth() - a
print "Root bp: "; basedepth() - b
PRINT Bar()
print "Root sp: "; stackdepth() - a
print "Root bp: "; basedepth() - b
`, `
Root sp: 0
Root bp: 0
Bar sp: 32
Bar bp: 8
Foo sp: 72
Foo bp: 40
Bar sp: 32
Bar bp: 8
1
Root sp: 0
Root bp: 0
`);

<commit_msg>Adding test for DEF FN with no args.<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

var basic_test = require('./basic-tester.js');

basic_test.BASIC_TEST('Functions', 'Classic', `
DEF FNdist(x, y) = SQR(x^2 + y^2)
a = 3
b = 4
PRINT FNdist(a, b)
`, `
5
`);

basic_test.BASIC_TEST('Functions', 'ClassicArgless', `
a$ = "hello"
b$ = "..."
DEF fnfoo$ = a$ + b$
print fnfoo$
a$ = "there"
print fnfoo$
`, `
hello...
there...
`);

basic_test.BASIC_TEST('Functions', 'NewStyle', `
FUNCTION Dist(x, y)
  Dist = SQR(x^2 + y^2)
END FUNCTION
a = 3
b = 4
PRINT Dist(a, b)
`, `
5
`);

basic_test.BASIC_TEST('Functions', 'CallLayers', `
FUNCTION Inc(x)
  Inc = x + 1
END FUNCTION
PRINT Inc(Inc(Inc(Inc(3))))
`, `
7
`);

basic_test.BASIC_TEST('Functions', 'DefLayers', `
FUNCTION Baz(x)
  Baz = x * 2
END FUNCTION

FUNCTION Bar(x)
  Bar = Baz(x) * 3
END FUNCTION

FUNCTION Foo(x)
  Foo = Bar(x) * 5
END FUNCTION

a = 1
PRINT Foo(a)
`, `
30
`);

basic_test.BASIC_TEST('Functions', 'RecursiveImplicit', `
FUNCTION Factorial(n)
  IF n = 0 OR n = 1 THEN
    Factorial = 1
  ELSE
    Factorial = n * Factorial(n - 1)
  END IF
END FUNCTION

a = 4
PRINT Factorial(a)
`, `
24
`);

basic_test.BASIC_TEST('Functions', 'RecursiveExplicit', `
FUNCTION Factorial(n AS INTEGER) AS INTEGER
  IF n = 0 OR n = 1 THEN
    Factorial = 1
  ELSE
    Factorial = n * Factorial(n - 1)
  END IF
END FUNCTION

a = 4
PRINT Factorial(a)
`, `
24
`);

basic_test.BASIC_TEST('Functions', 'RecursiveExplicitWithLocal', `
FUNCTION Factorial(n AS INTEGER) AS INTEGER
  IF n = 0 OR n = 1 THEN
    Factorial = 1
  ELSE
    temp = n * Factorial(n - 1)
    Factorial = temp
  END IF
END FUNCTION

a = 4
PRINT Factorial(a)
`, `
24
`);

basic_test.BASIC_TEST('Functions', 'Predeclare', `
DECLARE FUNCTION Adder(x AS INTEGER, y AS INTEGER) AS INTEGER
PRINT Adder(1, 2)
FUNCTION Adder(x AS INTEGER, y AS INTEGER) AS INTEGER
  Adder = x + y
END FUNCTION
`, `
3
`);

basic_test.BASIC_TEST('Functions', 'ByRef', `
FUNCTION Changer(x as INTEGER)
  x = 2
  Changer = 3
END FUNCTION
a = 1
PRINT Changer(a)
PRINT a
`, `
3
2
`);

basic_test.BASIC_TEST('Functions', 'Multi', `
FUNCTION Plus1(x as INTEGER)
  Plus1 = x + 1
END FUNCTION
PRINT Plus1(3) + Plus1(4) + Plus1(6)
`, `
16
`);

basic_test.BASIC_TEST('Functions', 'TreeSize', `
FUNCTION TreeSize(n)
  IF n = 1 THEN
    TreeSize = 1
  ELSE
    TreeSize = TreeSize(n - 1) + TreeSize(n - 1) + 1
  END IF
END FUNCTION
PRINT TreeSize(5)
`, `
31
`);

basic_test.BASIC_TEST('Subroutines', 'Depth', `
a = stackdepth()
b = basedepth()

FUNCTION Foo(a$)
  b$ = a$
  print "Foo sp: "; stackdepth() - a
  print "Foo bp: "; basedepth() - b
  Foo = 1
END FUNCTION

FUNCTION Bar()
  print "Bar sp: "; stackdepth() - a
  print "Bar bp: "; basedepth() - b
  Bar = Foo("hi")
  print "Bar sp: "; stackdepth() - a
  print "Bar bp: "; basedepth() - b
END FUNCTION

print "Root sp: "; stackdepth() - a
print "Root bp: "; basedepth() - b
PRINT Bar()
print "Root sp: "; stackdepth() - a
print "Root bp: "; basedepth() - b
`, `
Root sp: 0
Root bp: 0
Bar sp: 32
Bar bp: 8
Foo sp: 72
Foo bp: 40
Bar sp: 32
Bar bp: 8
1
Root sp: 0
Root bp: 0
`);

<|endoftext|>