RabsRincon | 6ef87b5 | 2018-02-27 14:58:21 +0100 | [diff] [blame] | 1 | // Copyright (c) 2017, Matt Godbolt |
Matt Godbolt | a272ea9 | 2017-12-10 16:52:53 -0600 | [diff] [blame] | 2 | // All rights reserved. |
| 3 | // |
| 4 | // Redistribution and use in source and binary forms, with or without |
| 5 | // modification, are permitted provided that the following conditions are met: |
| 6 | // |
| 7 | // * Redistributions of source code must retain the above copyright notice, |
| 8 | // this list of conditions and the following disclaimer. |
| 9 | // * Redistributions in binary form must reproduce the above copyright |
| 10 | // notice, this list of conditions and the following disclaimer in the |
| 11 | // documentation and/or other materials provided with the distribution. |
| 12 | // |
| 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 16 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| 17 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 18 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 19 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 20 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 21 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 22 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 23 | // POSSIBILITY OF SUCH DAMAGE. |
| 24 | |
| 25 | const chai = require('chai'), |
RabsRincon | e567783 | 2018-07-02 08:57:21 +0200 | [diff] [blame] | 26 | utils = require('../lib/utils'), |
RabsRincon | bdc447f | 2018-08-20 11:10:23 +0200 | [diff] [blame] | 27 | logger = require('../lib/logger').logger, |
| 28 | fs = require('fs-extra'); |
Matt Godbolt | a272ea9 | 2017-12-10 16:52:53 -0600 | [diff] [blame] | 29 | |
| 30 | chai.should(); |
| 31 | |
| 32 | describe('Splits lines', () => { |
| 33 | it('handles empty input', () => { |
| 34 | utils.splitLines('').should.deep.equals([]); |
| 35 | }); |
| 36 | it('handles a single line with no newline', () => { |
| 37 | utils.splitLines('A line').should.deep.equals(['A line']); |
| 38 | }); |
| 39 | it('handles a single line with a newline', () => { |
| 40 | utils.splitLines('A line\n').should.deep.equals(['A line']); |
| 41 | }); |
| 42 | it('handles multiple lines', () => { |
| 43 | utils.splitLines('A line\nAnother line\n').should.deep.equals(['A line', 'Another line']); |
| 44 | }); |
| 45 | it('handles multiple lines ending on a non-newline', () => { |
| 46 | utils.splitLines('A line\nAnother line\nLast line').should.deep.equals( |
| 47 | ['A line', 'Another line', 'Last line']); |
| 48 | }); |
| 49 | it('handles empty lines', () => { |
| 50 | utils.splitLines('A line\n\nA line after an empty').should.deep.equals( |
| 51 | ['A line', '', 'A line after an empty']); |
| 52 | }); |
| 53 | it('handles a single empty line', () => { |
| 54 | utils.splitLines('\n').should.deep.equals(['']); |
| 55 | }); |
| 56 | it('handles multiple empty lines', () => { |
| 57 | utils.splitLines('\n\n\n').should.deep.equals(['', '', '']); |
| 58 | }); |
| 59 | it('handles \\r\\n lines', () => { |
| 60 | utils.splitLines('Some\r\nLines\r\n').should.deep.equals(['Some', 'Lines']); |
| 61 | }); |
| 62 | }); |
| 63 | |
| 64 | describe('Expands tabs', () => { |
| 65 | it('leaves non-tabs alone', () => { |
| 66 | utils.expandTabs('This has no tabs at all').should.equals('This has no tabs at all'); |
| 67 | }); |
| 68 | it('at beginning of line', () => { |
| 69 | utils.expandTabs('\tOne tab').should.equals(' One tab'); |
| 70 | utils.expandTabs('\t\tTwo tabs').should.equals(' Two tabs'); |
| 71 | }); |
| 72 | it('mid-line', () => { |
| 73 | utils.expandTabs('0\t1234567A').should.equals('0 1234567A'); |
| 74 | utils.expandTabs('01\t234567A').should.equals('01 234567A'); |
| 75 | utils.expandTabs('012\t34567A').should.equals('012 34567A'); |
| 76 | utils.expandTabs('0123\t4567A').should.equals('0123 4567A'); |
| 77 | utils.expandTabs('01234\t567A').should.equals('01234 567A'); |
| 78 | utils.expandTabs('012345\t67A').should.equals('012345 67A'); |
| 79 | utils.expandTabs('0123456\t7A').should.equals('0123456 7A'); |
| 80 | utils.expandTabs('01234567\tA').should.equals('01234567 A'); |
| 81 | }); |
| 82 | }); |
| 83 | |
| 84 | describe('Parses compiler output', () => { |
| 85 | it('handles simple cases', () => { |
| 86 | utils.parseOutput('Line one\nLine two', 'bob.cpp').should.deep.equals([ |
| 87 | {text: 'Line one'}, |
| 88 | {text: 'Line two'} |
| 89 | ]); |
| 90 | utils.parseOutput('Line one\nbob.cpp:1 Line two', 'bob.cpp').should.deep.equals([ |
| 91 | {text: 'Line one'}, |
| 92 | { |
| 93 | tag: {column: 0, line: 1, text: "Line two"}, |
| 94 | text: '<source>:1 Line two' |
| 95 | } |
| 96 | ]); |
| 97 | utils.parseOutput('Line one\nbob.cpp:1:5: Line two', 'bob.cpp').should.deep.equals([ |
| 98 | {text: 'Line one'}, |
| 99 | { |
| 100 | tag: {column: 5, line: 1, text: "Line two"}, |
| 101 | text: '<source>:1:5: Line two' |
| 102 | } |
| 103 | ]); |
| 104 | }); |
| 105 | it('handles windows output', () => { |
| 106 | utils.parseOutput('bob.cpp(1) Oh noes', 'bob.cpp').should.deep.equals([ |
| 107 | { |
| 108 | tag: {column: 0, line: 1, text: 'Oh noes'}, |
| 109 | text: '<source>(1) Oh noes' |
| 110 | } |
| 111 | ]); |
| 112 | }); |
| 113 | it('replaces all references to input source', () => { |
| 114 | utils.parseOutput('bob.cpp:1 error in bob.cpp', 'bob.cpp').should.deep.equals([ |
| 115 | { |
| 116 | tag: {column: 0, line: 1, text: 'error in <source>'}, |
| 117 | text: '<source>:1 error in <source>' |
| 118 | } |
| 119 | ]); |
| 120 | }); |
Matt Godbolt | 3baf2a2 | 2017-12-19 08:00:34 -0600 | [diff] [blame] | 121 | it('treats <stdin> as if it were the compiler source', () => { |
| 122 | utils.parseOutput('<stdin>:120:25: error: variable or field \'transform_data\' declared void', 'bob.cpp') |
| 123 | .should.deep.equals([ |
| 124 | { |
| 125 | tag: { |
| 126 | column: 25, |
| 127 | line: 120, |
| 128 | text: 'error: variable or field \'transform_data\' declared void' |
| 129 | }, |
| 130 | text: '<source>:120:25: error: variable or field \'transform_data\' declared void' |
| 131 | } |
| 132 | ]); |
| 133 | }); |
Matt Godbolt | a272ea9 | 2017-12-10 16:52:53 -0600 | [diff] [blame] | 134 | }); |
| 135 | |
Partouf | f0f7452 | 2018-03-15 17:46:24 +0100 | [diff] [blame] | 136 | describe('Pascal compiler output', () => { |
| 137 | it('recognize fpc identifier not found error', () => { |
| 138 | utils.parseOutput('output.pas(13,23) Error: Identifier not found "adsadasd"', 'output.pas').should.deep.equals([ |
| 139 | { |
| 140 | tag: { |
| 141 | column: 23, |
| 142 | line: 13, |
| 143 | text: 'Error: Identifier not found "adsadasd"' |
| 144 | }, |
| 145 | text: '<source>(13,23) Error: Identifier not found "adsadasd"' |
| 146 | } |
| 147 | ]); |
| 148 | }); |
| 149 | |
| 150 | it('recognize fpc exiting error', () => { |
| 151 | utils.parseOutput('output.pas(17) Fatal: There were 1 errors compiling module, stopping', 'output.pas').should.deep.equals([ |
| 152 | { |
| 153 | tag: { |
| 154 | column: 0, |
| 155 | line: 17, |
| 156 | text: 'Fatal: There were 1 errors compiling module, stopping' |
| 157 | }, |
| 158 | text: '<source>(17) Fatal: There were 1 errors compiling module, stopping' |
| 159 | } |
| 160 | ]); |
| 161 | }); |
Partouf | a58689b | 2018-03-15 18:03:21 +0100 | [diff] [blame] | 162 | |
| 163 | it('removes the temp path', () => { |
| 164 | utils.parseOutput('Compiling /tmp/path/prog.dpr\noutput.pas(17) Fatal: There were 1 errors compiling module, stopping', 'output.pas', '/tmp/path/').should.deep.equals([ |
| 165 | { |
| 166 | text: 'Compiling prog.dpr' |
| 167 | }, |
| 168 | { |
| 169 | tag: { |
| 170 | column: 0, |
| 171 | line: 17, |
| 172 | text: 'Fatal: There were 1 errors compiling module, stopping' |
| 173 | }, |
| 174 | text: '<source>(17) Fatal: There were 1 errors compiling module, stopping' |
| 175 | } |
| 176 | ]); |
| 177 | }); |
Partouf | f0f7452 | 2018-03-15 17:46:24 +0100 | [diff] [blame] | 178 | }); |
| 179 | |
Matt Godbolt | a272ea9 | 2017-12-10 16:52:53 -0600 | [diff] [blame] | 180 | describe('Pads right', () => { |
| 181 | it('works', () => { |
| 182 | utils.padRight('abcd', 8).should.equal('abcd '); |
| 183 | utils.padRight('a', 8).should.equal('a '); |
| 184 | utils.padRight('', 8).should.equal(' '); |
| 185 | utils.padRight('abcd', 4).should.equal('abcd'); |
| 186 | utils.padRight('abcd', 2).should.equal('abcd'); |
| 187 | }); |
| 188 | }); |
RabsRincon | 12026f6 | 2018-06-28 02:23:38 +0200 | [diff] [blame] | 189 | |
Kārlis Seņko | 40f6e0e | 2019-01-08 00:41:07 +0200 | [diff] [blame] | 190 | describe('Trim right', () => { |
| 191 | it('works', () => { |
| 192 | utils.trimRight(' ').should.equal(''); |
| 193 | utils.trimRight('').should.equal(''); |
| 194 | utils.trimRight(' ab ').should.equal(' ab'); |
| 195 | utils.trimRight(' a b ').should.equal(' a b'); |
| 196 | utils.trimRight('a ').should.equal('a'); |
| 197 | }); |
| 198 | }); |
| 199 | |
RabsRincon | 12026f6 | 2018-06-28 02:23:38 +0200 | [diff] [blame] | 200 | describe('Anonymizes all kind of IPs', () => { |
| 201 | it('Ignores localhost', () => { |
| 202 | utils.anonymizeIp('localhost').should.equal('localhost'); |
| 203 | utils.anonymizeIp('localhost:42').should.equal('localhost:42'); |
| 204 | }); |
| 205 | it('Removes last octet from IPv4 addresses', () => { |
| 206 | utils.anonymizeIp('127.0.0.0').should.equal('127.0.0.0'); |
| 207 | utils.anonymizeIp('127.0.0.10').should.equal('127.0.0.0'); |
| 208 | utils.anonymizeIp('127.0.0.255').should.equal('127.0.0.0'); |
| 209 | }); |
RabsRincon | dd2ab6d | 2018-07-04 17:54:23 +0200 | [diff] [blame] | 210 | it('Removes last 3 hextets from IPv6 addresses', () => { |
RabsRincon | 12026f6 | 2018-06-28 02:23:38 +0200 | [diff] [blame] | 211 | // Not necessarily valid addresses, we're interested in the format |
| 212 | utils.anonymizeIp('ffff:aaaa:dead:beef').should.equal('ffff:0:0:0'); |
| 213 | utils.anonymizeIp('bad:c0de::').should.equal('bad:0:0:0'); |
| 214 | utils.anonymizeIp(':1d7e::c0fe').should.equal(':0:0:0'); |
| 215 | }); |
| 216 | }); |
RabsRincon | e567783 | 2018-07-02 08:57:21 +0200 | [diff] [blame] | 217 | |
| 218 | describe('Logger functionality', () => { |
| 219 | it('has info stream with a write function', () => { |
| 220 | logger.stream.write.should.a("function"); |
| 221 | }); |
RabsRincon | 1e053fd | 2018-07-04 18:52:13 +0200 | [diff] [blame] | 222 | it('has warning stream with a write function', () => { |
RabsRincon | e567783 | 2018-07-02 08:57:21 +0200 | [diff] [blame] | 223 | logger.warnStream.write.should.a("function"); |
| 224 | }); |
RabsRincon | 1e053fd | 2018-07-04 18:52:13 +0200 | [diff] [blame] | 225 | it('has error stream with a write function', () => { |
RabsRincon | e567783 | 2018-07-02 08:57:21 +0200 | [diff] [blame] | 226 | logger.errStream.write.should.a("function"); |
| 227 | }); |
| 228 | }); |
RabsRincon | 1e053fd | 2018-07-04 18:52:13 +0200 | [diff] [blame] | 229 | |
| 230 | describe('Hash interface', () => { |
| 231 | it('correctly hashes strings', () => { |
| 232 | const version = 'Compiler Explorer Tests Version 0'; |
| 233 | utils.getHash('cream cheese', version).should.equal('cfff2d1f7a213e314a67cce8399160ae884f794a3ee9d4a01cd37a8c22c67d94'); |
| 234 | utils.getHash('large eggs', version).should.equal('9144dec50b8df5bc5cc24ba008823cafd6616faf2f268af84daf49ac1d24feb0'); |
| 235 | utils.getHash('sugar', version).should.equal('afa3c89d0f6a61de6805314c9bd7c52d020425a3a3c7bbdfa7c0daec594e5ef1'); |
| 236 | }); |
| 237 | it('correctly hashes objects', () => { |
Matt Godbolt | 2e7fc5f | 2019-03-21 21:28:43 -0500 | [diff] [blame] | 238 | utils.getHash({ |
| 239 | toppings: [ |
| 240 | {name: 'raspberries', optional: false}, |
| 241 | {name: 'ground cinnamon', optional: true} |
| 242 | ] |
| 243 | }).should.equal('e205d63abd5db363086621fdc62c4c23a51b733bac5855985a8b56642d570491'); |
RabsRincon | 1e053fd | 2018-07-04 18:52:13 +0200 | [diff] [blame] | 244 | }); |
| 245 | }); |
RabsRincon | bdc447f | 2018-08-20 11:10:23 +0200 | [diff] [blame] | 246 | |
| 247 | describe('GoldenLayout utils', () => { |
| 248 | it('finds every editor & compiler', () => { |
| 249 | fs.readJson('test/example-states/default-state.json') |
| 250 | .then(state => { |
| 251 | const contents = utils.glGetMainContents(state.content); |
| 252 | contents.should.deep.equal({ |
| 253 | editors: [ |
| 254 | {source: 'Editor 1', language: 'c++'}, |
| 255 | {source: 'Editor 2', language: 'c++'}, |
| 256 | {source: 'Editor 3', language: 'c++'}, |
| 257 | {source: 'Editor 4', language: 'c++'} |
| 258 | ], |
| 259 | compilers: [ |
| 260 | {compiler: 'clang_trunk'}, |
| 261 | {compiler: 'gsnapshot'}, |
| 262 | {compiler: 'clang_trunk'}, |
| 263 | {compiler: 'gsnapshot'}, |
| 264 | {compiler: 'rv32clang'} |
| 265 | ] |
Matt Godbolt | 2e7fc5f | 2019-03-21 21:28:43 -0500 | [diff] [blame] | 266 | }); |
RabsRincon | bdc447f | 2018-08-20 11:10:23 +0200 | [diff] [blame] | 267 | }); |
Matt Godbolt | 2e7fc5f | 2019-03-21 21:28:43 -0500 | [diff] [blame] | 268 | }); |
RabsRincon | bdc447f | 2018-08-20 11:10:23 +0200 | [diff] [blame] | 269 | }); |
Andre Meyering | 061dcd3 | 2018-07-07 14:57:56 +0200 | [diff] [blame] | 270 | |
Matt Godbolt | 2e7fc5f | 2019-03-21 21:28:43 -0500 | [diff] [blame] | 271 | describe('squashes horizontal whitespace', () => { |
Andre Meyering | 061dcd3 | 2018-07-07 14:57:56 +0200 | [diff] [blame] | 272 | it('handles empty input', () => { |
Matt Godbolt | 2e7fc5f | 2019-03-21 21:28:43 -0500 | [diff] [blame] | 273 | utils.squashHorizontalWhitespace('').should.equals(''); |
| 274 | utils.squashHorizontalWhitespace(' ').should.equals(''); |
| 275 | utils.squashHorizontalWhitespace(' ').should.equals(''); |
Andre Meyering | 061dcd3 | 2018-07-07 14:57:56 +0200 | [diff] [blame] | 276 | }); |
| 277 | it('handles leading spaces', () => { |
Matt Godbolt | 2e7fc5f | 2019-03-21 21:28:43 -0500 | [diff] [blame] | 278 | utils.squashHorizontalWhitespace(' abc').should.equals(' abc'); |
| 279 | utils.squashHorizontalWhitespace(' abc').should.equals(' abc'); |
| 280 | utils.squashHorizontalWhitespace(' abc').should.equals(' abc'); |
Andre Meyering | 061dcd3 | 2018-07-07 14:57:56 +0200 | [diff] [blame] | 281 | }); |
| 282 | it('handles interline spaces', () => { |
Matt Godbolt | 2e7fc5f | 2019-03-21 21:28:43 -0500 | [diff] [blame] | 283 | utils.squashHorizontalWhitespace('abc abc').should.equals('abc abc'); |
| 284 | utils.squashHorizontalWhitespace('abc abc').should.equals('abc abc'); |
| 285 | utils.squashHorizontalWhitespace('abc abc').should.equals('abc abc'); |
Andre Meyering | 061dcd3 | 2018-07-07 14:57:56 +0200 | [diff] [blame] | 286 | }); |
| 287 | it('handles leading and interline spaces', () => { |
Matt Godbolt | 2e7fc5f | 2019-03-21 21:28:43 -0500 | [diff] [blame] | 288 | utils.squashHorizontalWhitespace(' abc abc').should.equals(' abc abc'); |
| 289 | utils.squashHorizontalWhitespace(' abc abc').should.equals(' abc abc'); |
| 290 | utils.squashHorizontalWhitespace(' abc abc').should.equals(' abc abc'); |
| 291 | utils.squashHorizontalWhitespace(' abc abc').should.equals(' abc abc'); |
Andre Meyering | 061dcd3 | 2018-07-07 14:57:56 +0200 | [diff] [blame] | 292 | }); |
| 293 | }); |