diff --git a/.editorconfig b/.editorconfig index e291365a..9d08a1a8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,7 +3,7 @@ root = true [*] charset = utf-8 indent_style = space -indent_size = 4 +indent_size = 2 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true diff --git a/README.md b/README.md index f4d13e0b..c28e5b1f 100644 --- a/README.md +++ b/README.md @@ -70,49 +70,50 @@ Many languages are currently supported in various states of completeness. This l **Legend:** `!!!` = Failing Specs, `???` = Status is unknown, `*` = Any -| Language | Version | Basic Run | Test Integration | Codewars | Qualified | Docker Image | Examples | Notes | -|----------------|---------------|--------------|------------------|---------------|----------------|----------------|--------------|-------------------------------------------------------------------------| -| Assembly (GAS) | | !!! | | | | systems-runner | | Travis is failing, tests pass locally | -| Bash | | ✓ | | Kumite Only | | * | | | -| C | Clang 3.6/C11 | ✓ | criterion | criterion | | systems-runner | | | -| Clojure | 1.6.0 | ✓ | clojure.test | clojure.test | clojure.test | jvm-runner | clojure.test | | -| CoffeeScript | 1.10.0 | ✓ | cw-2 | cw-2 | cw-2 | node-runner | cw-2 | | -| C++ | 14 | ✓ | igloo | igloo | | systems-runner | | | -| C# | Mono 4.8 | ✓ | nunit | nunit | nunit | dotnet-runner | nunit | | -| Crystal | 0.21.1 | ✓ | spec | spec | spec | crystal-runner | spec | | -| Dart | 1.16.1 | ✓ | test | Kumite Only | | dart-runner | test | | -| Elixir | 1.2.4 | ✓ | exunit | exunit | | erlang-runner | | | -| Erlang | 18 | ✓ | | | | erlang-runner | | | -| F# | 4.0 | ✓ | fuchu | fuchu | | dotnet-runner | Fuchu | Tests should be placed in a module called "Tests", in a Fuchu testList | -| Go | 1.3.1 | ✓ | | Kumite Only | | alt-runner | | | -| Groovy | | ✓ | | Kumite Only | | jvm-runner | | | -| Haskell | 7.6.3 | ✓ | hspec!!! | hspec | hspec | haskell-runner | hspec | An older version is running on CW & Qualified that is fully functional | -| Java | 1.8.0_91 | ✓ | junit | Yes | Yes | jvm-runner | junit | | -| JavaScript | 0.10.33 | ✓ | cw-2, mocha | cw-2 | cw-2, mocha | node-runner | cw-2 | | -| JavaScript | 0.10.33/Babel | ✓ | cw-2, mocha | cw-2 | cw-2, mocha | node-runner | cw-2 | | -| JavaScript | 6.0.0 | ✓ | cw-2, mocha | cw-2 | cw-2, mocha | node-runner | cw-2 | | -| JavaScript | 6.0.0/Babel | ✓ | cw-2, mocha | cw-2 | cw-2, mocha | node-runner | cw-2 | | -| Julia | 0.4.6 | ✓ | factcheck | factcheck | | | | | -| Kotlin | 1.0.3 | ✓ | ??? | | | jvm-runner | | | -| Lisp | | ✓ | | Kumite Only | | func-runner | | | -| Lua | | ✓ | | Kumite Only | | alt-runner | | | -| Objective-C | 2.0 | ✓ | cw | cw | | objc-runner | | | -| OCAML | 4.02.3 | ✓ | ounit | ounit | | ocaml-runner | | Tests should be placed in a module called "Tests", in an array of OUnit labels named "suite" | -| Perl | | ✓ | | Kumite Only | | * | | | -| Php | 7.0 | ✓ | cw-2, phpunit | phpunit | phpunit, cw-2 | alt-runner | | | -| Python | 2.7.6 | ✓ | cw-2, unittest | cw-2 | cw-2, unittest | python-runner | cw-2 | | -| Python | 3.4.3 | ✓ | cw-2, unittest | | cw-2, unittest | python-runner | cw-2 | | -| R | | ✓ | | | | alt-runner | | | -| Racket | | ✓ | | Kumite Only | | func-runner | | | -| Ruby | 2.3.0 | ✓ | cw-2, rspec | cw-2 | cw-2, rspec | ruby-runner | cw-2 | | -| Rust | 1.10.0 | ✓ | rust | rust | | | | | -| Scala | 2.11.2 | ✓ | | Kumite Only | | jvm-runner | | | -| Scss/Sass | | ??? | ??? | | | | | | -| SQL | SQLite3 | ✓ | rspec | | | | | Current contribution designed for OSX, need to move to OS linux version | -| SQL | Postgres 9.6 | ✓ | rspec | | | | | Current contribution designed for OSX, need to move to OS linux version | -| Swift | 3.0-dev | ✓ | cw-2, xctest | xctest | | | | Current contribution designed for OSX, need to move to OS linux version | -| TypeScript | 1.8.10 | ✓ | mocha | mocha | | node-runner | | TypeScript utilizes `require` instead of concatenating files | - +| Language | Version | Basic Run | Project Mode | Test Integration | Codewars | Qualified | Docker Image | Examples | Notes | +|----------------|---------------|------------|--------------|------------------|----------------|----------------|--------------|---------------| ------------------------------------------------------------------------| +| Assembly (GAS) | | !!! | | | | | systems-runner | | Travis is failing, tests pass locally | +| Bash | | ✓ | ✓ | | Kumite Only | | * | | | +| C | Clang 3.6/C11 | ✓ | | criterion | criterion | | systems-runner | | | +| Clojure | 1.6.0 | ✓ | | clojure.test | clojure.test | clojure.test | jvm-runner | clojure.test | | +| CoffeeScript | 1.10.0 | ✓ | | cw-2 | cw-2 | cw-2 | node-runner | cw-2 | | +| C++ | 14 | ✓ | | igloo | igloo | | systems-runner | | | +| C# | Mono 4.8 | ✓ | ✓ | nunit | nunit | nunit | dotnet-runner | nunit | | +| Crystal | 0.21.1 | ✓ | | spec | spec | spec | crystal-runner | spec | | +| Dart | 1.16.1 | ✓ | | test | Kumite Only | | dart-runner | test | | +| Elixir | 1.2.4 | ✓ | | exunit | exunit | | erlang-runner | | | +| Erlang | 18 | ✓ | | | | | erlang-runner | | | +| F# | 4.0 | ✓ | | fuchu | fuchu | | dotnet-runner | Fuchu | Tests should be placed in a module called "Tests", in a Fuchu testList | +| Go | 1.8 | ✓ | | ginkgo | ginkgo | | go-runner | ginkgo | | +| Groovy | | ✓ | | | Kumite Only | | jvm-runner | | | +| Haskell | 7.6.3 | ✓ | | hspec!!! | hspec | hspec | haskell-runner | hspec | An older version is running on CW & Qualified that is fully functional | +| Java | 1.8.0_91 | ✓ | | junit | Yes | Yes | jvm-runner | junit | | +| JavaScript | 0.10.33 | ✓ | ✓ | cw-2 | cw-2 | cw-2, | node-runner | cw-2 | | +| JavaScript | 0.10.33/Babel | ✓ | ✓ | cw-2 | cw-2 | cw-2, | node-runner | cw-2 | | +| JavaScript | 6.0.0 | ✓ | ✓ | cw-2, mocha | cw-2 | cw-2, mocha | node-runner | cw-2 | | +| JavaScript | 6.0.0/Babel | ✓ | ✓ | cw-2, mocha | cw-2 | cw-2, mocha | node-runner | cw-2 | | +| Julia | 0.4.6 | ✓ | | factcheck | factcheck | | | | | +| Kotlin | 1.0.3 | ✓ | | ??? | | | jvm-runner | | | +| Lisp | | ✓ | | | Kumite Only | | func-runner | | | +| Lua | 5.2 | ✓ | | busted | busted | | lua-runner | | | +| Objective-C | 2.0 | ✓ | | cw | cw | | objc-runner | | | +| OCAML | 4.02.3 | ✓ | | ounit | ounit | | ocaml-runner | | Tests should be placed in a module called "Tests", in an array of OUnit labels named "suite" | +| Perl | | ✓ | | | Kumite Only | | * | | | +| Php | 7.0 | ✓ | | cw-2, phpunit | phpunit | phpunit, cw-2 | alt-runner | | | +| Python | 2.7.6 | ✓ | ✓ | cw-2, unittest | cw-2 | cw-2, unittest | python-runner | cw-2 | | +| Python | 3.4.3 | ✓ | ✓ | cw-2, unittest | | cw-2, unittest | python-runner | cw-2 | | +| Python | 3.6 | ✓ | ✓ | cw-2, unittest | | cw-2, unittest | python-runner | cw-2 | | +| R | | ✓ | | | | | alt-runner | | | +| Racket | | ✓ | | | Kumite Only | | func-runner | | | +| Ruby | 2.3.0 | ✓ | ✓ | cw-2, rspec | cw-2 | cw-2, rspec | ruby-runner | cw-2 | | +| Rust | 1.10.0 | ✓ | | rust | rust | | | | | +| Scala | 2.11.2 | ✓ | | | Kumite Only | | jvm-runner | | | +| Scss/Sass | | ??? | | ??? | | | | | | +| SQL | SQLite3 | ✓ | ✓ | rspec | | | | | Current contribution designed for OSX, need to move to OS linux version | +| SQL | Postgres 9.6 | ✓ | ✓ | rspec | | | | | Current contribution designed for OSX, need to move to OS linux version | +| Swift | 3.0-dev | ✓ | | cw-2, xctest | xctest | | | | Current contribution designed for OSX, need to move to OS linux version | +| TypeScript | 1.8.10 | ✓ | | mocha | mocha | | node-runner | | TypeScript utilizes `require` instead of concatenating files | + ## Setup You should have [Docker](https://www.docker.com/) installed, if not do that first. Before you can run any of the code diff --git a/frameworks/ruby/sql.rb b/frameworks/ruby/sql.rb index 810997f3..c1c21538 100644 --- a/frameworks/ruby/sql.rb +++ b/frameworks/ruby/sql.rb @@ -18,7 +18,9 @@ def select_cmd?(cmd) end def run_cmd(cmd) - select_cmd?(cmd) ? DB[cmd] : DB.run(cmd) + try_connection do + select_cmd?(cmd) ? DB[cmd] : DB.run(cmd) + end end def split_sql_commands(sql) @@ -122,8 +124,26 @@ def pluck_unique(column_name, results = last_results) results.map {|r| r[column_name]}.uniq end +def try_connection + begin + yield + rescue Sequel::DatabaseConnectionError => cex + Display.status "Connection error: #{cex.message}, retrying in 1 second..." + sleep 1 + retry + rescue => ex + if defined?(PG::ConnectionBad) + if ex.is_a?(PG::ConnectionBad) + sleep 1 + Display.status "Connection not ready, retrying in 1 second..." + retry + end + end + end +end + # connect the database -begin +try_connection do Display.status "Connecting to database..." # Setup database connection DATABASE = ENV['DATABASE_NAME'] @@ -144,15 +164,4 @@ def expected end END end - -rescue => ex - if defined?(PG::ConnectionBad) - if ex.is_a?(PG::ConnectionBad) - sleep 1 - Display.status "Connection not ready, retrying in 1 second..." - retry - end - end end - - diff --git a/lib/runners/lua.js b/lib/runners/lua.js index 7d4cc643..1b5cb107 100644 --- a/lib/runners/lua.js +++ b/lib/runners/lua.js @@ -2,24 +2,24 @@ var shovel = require('../shovel'), writeFileSync = require('../util').writeFileSync; module.exports.run = function run(opts, cb) { - const dir = '/home/codewarrior/lua'; - shovel.start(opts, cb, { - solutionOnly: function(runCode) { - runCode({ - name: 'lua', - args: [writeFileSync(dir, 'solution.lua', opts.solution, true)] - }); - }, - testIntegration: function(runCode) { - writeFileSync(dir, 'solution.lua', opts.solution, true); - runCode({ - name: 'busted', - args: [ - writeFileSync(dir, 'fixture.lua', opts.fixture, true), - `--output=codewars.lua`, - ], - options: {cwd: dir} - }); - } - }); + const dir = '/home/codewarrior/lua'; + shovel.start(opts, cb, { + solutionOnly: function (runCode) { + runCode({ + name: 'lua', + args: [writeFileSync(dir, 'solution.lua', opts.solution, true)] + }); + }, + testIntegration: function (runCode) { + writeFileSync(dir, 'solution.lua', opts.solution, true); + runCode({ + name: 'busted', + args: [ + writeFileSync(dir, 'fixture.lua', opts.fixture, true), + `--output=codewars.lua`, + ], + options: {cwd: dir} + }); + } + }); }; diff --git a/lib/runners/php.js b/lib/runners/php.js index 737d9c3b..e4a973ab 100644 --- a/lib/runners/php.js +++ b/lib/runners/php.js @@ -1,48 +1,42 @@ var shovel = require('../shovel'), - util = require('../util'), - temp = require('temp'), - config = require('../config'); + util = require('../util'), + temp = require('temp'), + config = require('../config'); -module.exports.run = function run(opts, cb) -{ - shovel.start(opts, cb, { - solutionOnly: function (runCode) - { - var code = opts.solution; +module.exports.run = function run (opts, cb) { + shovel.start(opts, cb, { + solutionOnly: function (runCode) { + var code = opts.solution; - if (opts.setup) - { - code = opts.setup + ';\n' + code; - } + if (opts.setup) { + code = opts.setup + ';\n' + code; + } - runCode({name: 'php', 'args': ['-r', code]}); - }, - testIntegration: function (runCode) - { - switch (opts.testFramework) - { - case 'cw-2': - return prepareCw2(opts, runCode); - case 'phpunit': - return preparePHPUnit(opts, runCode); - default: - throw 'Test framework is not supported' - } - }, - sanitizeStdOut : function (output) { - var lines = output.split('\n'); - return filterLines(lines).join('\n'); - }, - sanitizeStdErr : function (error) { - error = error ? `\n${error}` : ''; - return error.replace(/(Uncaught Exception: Failed Test).*/g, '$1') - .replace(/\/runner\/.*\.php/g, 'input'); - } - }); + runCode({name: 'php', 'args': ['-r', code]}); + }, + testIntegration: function (runCode) { + switch (opts.testFramework) { + case 'cw-2': + return prepareCw2(opts, runCode); + case 'phpunit': + return preparePHPUnit(opts, runCode); + default: + throw 'Test framework is not supported' + } + }, + sanitizeStdOut: function (output) { + var lines = output.replace(" PHPUnit 5.7.15 by Sebastian Bergmann and contributors.", "").split('\n'); + return filterLines(lines).join('\n'); + }, + sanitizeStdErr: function (error) { + error = error ? `\n${error}` : ''; + return error.replace(/(Uncaught Exception: Failed Test).*/g, '$1').replace(/\/runner\/.*\.php/g, 'input'); + } + }); }; -function prepareCw2(opts, run) { - var code = ` +function prepareCw2 (opts, run) { + var code = ` require_once('frameworks/php/cw-2.php'); ${opts.setup || ''} ${opts.solution} @@ -50,11 +44,11 @@ function prepareCw2(opts, run) { ${opts.fixture} `; - run({name: 'php', 'args': ['-r', code]}); + run({name: 'php', 'args': ['-r', code]}); } -function preparePHPUnit(opts, run) { - var code = ` +function preparePHPUnit (opts, run) { + var code = ` `; - var file = util.codeWriteSync('php', code, opts.dir, 'run.php'); + var file = util.codeWriteSync('php', code, opts.dir, 'run.php'); - run({name: 'phpunit', 'args': ['--configuration=frameworks/php/phpunit/phpunit.xml', file]}); + run({name: 'phpunit', 'args': ['--configuration=frameworks/php/phpunit/phpunit.xml', file]}); } var filterLines = (function () { - var blacklist = [ - /^\s*$/, - /PHPUnit \d\.\d\.\d by Seb/, - /\s+\d \/ \d \(\d+\%\)/, - /^Time: \d+ ms, Memory:/, - /^There was \d+ failure/, - /^FAILURES!$/, - /^Tests: \d+, Assertions:/, - ]; + var blacklist = [ + /^\s*$/, + /PHPUnit \d\.\d\.\d by Seb/, + /\s+\d \/ \d \(\d+\%\)/, + /^Time: \d+ ms, Memory:/, + /^There was \d+ failure/, + /^FAILURES!$/, + /^Tests: \d+, Assertions:/, + ]; - /** - * Strip lines from output we don't want - * - * @param array lines - * @return array - */ - return function (lines) { - return lines - .filter(function (line) { - return blacklist.every(function (regex) { - return !regex.test(line); - }); - }) - .map(function(line) { - // clean up filenames - if(/\/tmp.*\.php/.test(line)) { - line = line.replace(/\/tmp\/[^\/]+\//, ''); - } - return line; - }); - }; -}()); \ No newline at end of file + /** + * Strip lines from output we don't want + * + * @param array lines + * @return array + */ + return function (lines) { + return lines.filter(function (line) { + return blacklist.every(function (regex) { + return !regex.test(line); + }); + }).map(function (line) { + // clean up filenames + if (/\/tmp.*\.php/.test(line)) { + line = line.replace(/\/tmp\/[^\/]+\//, ''); + } + return line; + }); + }; +}()); diff --git a/lib/runners/ruby.js b/lib/runners/ruby.js index a7418839..29bd4228 100644 --- a/lib/runners/ruby.js +++ b/lib/runners/ruby.js @@ -1,124 +1,110 @@ var shovel = require('../shovel'), - util = require('../util'), - temp = require('temp'); - -module.exports.run = function run(opts, cb) -{ - shovel.start(opts, cb, { - modifyOpts: function() { - // if a github repo was provided, add the workspace to the load path so that requires work correctly - if (opts.githubRepo || opts.files || opts.gist) { - opts.setup = `$LOAD_PATH << '/home/codewarrior'\n${opts.setup || ''}`; - } - }, - solutionOnly: function (runCode) - { - var code = opts.solution; - - if (opts.setup) - { - code = opts.setup + '\n' + code; - } - - runCode({name: 'ruby', args: ['-e', code], options: {cwd: opts.dir}}); - }, - testIntegration: function (runCode) - { - switch (opts.testFramework) - { - case 'cw': - case 'cw-2': - return prepareCw2(opts, runCode); - case 'rspec': - return prepareRSpec(opts, runCode); - - default: - throw 'Test framework is not supported' - } - }, - sanitizeStdErr: function(error) - { - return error.replace(/[\w/-]*(cw-2.rb):[\d]*:in( `(measure|wrap_error|it|describe)'<:LF:>)?/g, '') - .replace(/-e:[\d]*:in/g, '') - .replace(' ', ' ') - .replace(/<:LF:> `(block in )?(
|describe|it)'/g, '') - .replace(' ', ' '); - }, - sanitizeStdOut: function(stdout) - { - return this.sanitizeStdErr(stdout); - } - }); + util = require('../util'), + temp = require('temp'); + +module.exports.run = function run (opts, cb) { + shovel.start(opts, cb, { + modifyOpts: function () { + // if a github repo was provided, add the workspace to the load path so that requires work correctly + if (opts.githubRepo || opts.files || opts.gist) { + opts.setup = `$LOAD_PATH << '/home/codewarrior'\n${opts.setup || ''}`; + } + }, + solutionOnly: function (runCode) { + var code = opts.solution; + + if (opts.setup) { + code = opts.setup + '\n' + code; + } + + runCode({name: 'ruby', args: ['-e', code], options: {cwd: opts.dir}}); + }, + testIntegration: function (runCode) { + switch (opts.testFramework) { + case 'cw': + case 'cw-2': + return prepareCw2(opts, runCode); + case 'rspec': + return prepareRSpec(opts, runCode); + + default: + throw 'Test framework is not supported' + } + }, + sanitizeStdErr: function (error) { + return error.replace(/[\w/-]*(cw-2.rb):[\d]*:in( `(measure|wrap_error|it|describe)'<:LF:>)?/g, '').replace(/-e:[\d]*:in/g, '').replace(' ', ' ').replace(/<:LF:> `(block in )?(
|describe|it)'/g, '').replace(' ', ' '); + }, + sanitizeStdOut: function (stdout) { + return this.sanitizeStdErr(stdout); + } + }); }; -function prepareCw2(opts, exec) -{ - const requireFramework = "require('/runner/frameworks/ruby/cw-2')" - - // by default cw-2 concatenates files so this special option causes separate files to be used instead - if (opts.entryPath || opts.useSeparateFiles) { - exec({ - name: 'ruby', - args: [prepareEntryFile(opts, requireFramework)], - options: { cwd: opts.dir } - }); - } - else { - var code = [requireFramework]; - - if (opts.setup) - { - code.push(opts.setup); - } - - code.push(opts.solution); - code.push(opts.fixture); - - exec({ - name: 'ruby', - args: ['-e', code.join('\n')], - options: { cwd: opts.dir } - }); +function prepareCw2 (opts, exec) { + const requireFramework = "require('/runner/frameworks/ruby/cw-2')" + + // by default cw-2 concatenates files so this special option causes separate files to be used instead + if (opts.entryPath || opts.useSeparateFiles) { + exec({ + name: 'ruby', + args: [prepareEntryFile(opts, requireFramework)], + options: {cwd: opts.dir} + }); + } + else { + var code = [requireFramework]; + + if (opts.setup) { + code.push(opts.setup); } -} -function prepareRSpec(opts, exec) -{ + code.push(opts.solution); + code.push(opts.fixture); + exec({ - name: 'rspec', - args: [prepareEntryFile(opts), '--require', '/runner/frameworks/ruby/cwrspecformatter.rb', '--format', 'CwRSpecFormatter'], - options: { cwd: opts.dir } + name: 'ruby', + args: ['-e', code.join('\n')], + options: {cwd: opts.dir} }); + } +} + +function prepareRSpec (opts, exec) { + exec({ + name: 'rspec', + args: [prepareEntryFile(opts), '--require', '/runner/frameworks/ruby/cwrspecformatter.rb', '--format', 'CwRSpecFormatter'], + options: {cwd: opts.dir} + }); } // used when a single file will be used as the entry point. It will include the other files separately -function prepareEntryFile(opts, require) { - // if there is no require and an entryPath is provided than just use that file directly - if (!require && opts.entryPath) return opts.entryPath +function prepareEntryFile (opts, require) { + // if there is no require and an entryPath is provided than just use that file directly + if (!require && opts.entryPath) return opts.entryPath + + var entry = [ + "`rm -rf /workspace/entry.rb`", + require || '' + ]; + + if (opts.entryPath) { + entry.push(`require "${opts.entryPath}"`) + } + else { + if (opts.setup) { + entry.push(`require "${util.codeWriteSync('ruby', opts.setup, opts.dir, 'setup.rb')}"`); + // have the file remove itself from the file system after it is loaded, so that it cannot be read by users trying to solve + entry.push("`rm -rf /workspace/setup.rb`"); + } - var entry = [ - "`rm -rf /workspace/entry.rb`", - require || '' - ]; + entry.push(`require "${util.codeWriteSync('ruby', opts.solution, opts.dir, 'solution.rb')}"`); - if (opts.entryPath) { - entry.push(`require "${opts.entryPath}"`) - } - else { - if (opts.setup) { - entry.push(`require "${util.codeWriteSync('ruby', opts.setup, opts.dir, 'setup.rb')}"`); - // have the file remove itself from the file system after it is loaded, so that it cannot be read by users trying to solve - entry.push("`rm -rf /workspace/setup.rb`"); - } - - entry.push(`require "${util.codeWriteSync('ruby', opts.solution, opts.dir, 'solution.rb')}"`); - - if (opts.fixture) { - entry.push(`require "${util.codeWriteSync('ruby', opts.fixture, opts.dir, '.spec.rb')}"`) - } + if (opts.fixture) { + entry.push(`require "${util.codeWriteSync('ruby', opts.fixture, opts.dir, '.spec.rb')}"`) } + } - return util.codeWriteSync('ruby', entry.join('\n'), opts.dir, '.entry.rb'); + return util.codeWriteSync('ruby', entry.join('\n'), opts.dir, '.entry.rb'); } module.exports.prepareRSpec = prepareRSpec;