Skip to content
This repository has been archived by the owner on Oct 14, 2020. It is now read-only.

Commit

Permalink
Merge branch 'master' into fix/python-cw-2
Browse files Browse the repository at this point in the history
# Conflicts:
#	test/runners/python_spec.js
  • Loading branch information
Bubbler-4 committed Feb 17, 2018
2 parents c3c3f7d + f27653d commit 9a9e10c
Show file tree
Hide file tree
Showing 6 changed files with 383 additions and 8 deletions.
71 changes: 71 additions & 0 deletions frameworks/python/codewars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import unittest
import traceback
from time import perf_counter

class CodewarsTestRunner(object):
def __init__(self): pass
def run(self, test):
r = CodewarsTestResult()
s = perf_counter()
print("\n<DESCRIBE::>Tests")
try:
test(r)
finally:
pass
print("\n<COMPLETEDIN::>{:.4f}".format(1000*(perf_counter() - s)))
return r

__unittest = True
class CodewarsTestResult(unittest.TestResult):
def __init__(self):
super().__init__()
self.start = 0.0

def startTest(self, test):
print("\n<IT::>" + test._testMethodName)
super().startTest(test)
self.start = perf_counter()

def stopTest(self, test):
print("\n<COMPLETEDIN::>{:.4f}".format(1000*(perf_counter() - self.start)))
super().stopTest(test)

def addSuccess(self, test):
print("\n<PASSED::>Test Passed")
super().addSuccess(test)

def addError(self, test, err):
print("\n<ERROR::>Unhandled Exception")
print("\n<LOG:ESC:Error>" + esc(''.join(traceback.format_exception_only(err[0], err[1]))))
print("\n<LOG:ESC:Traceback>" + esc(self._exc_info_to_string(err, test)))
super().addError(test, err)

def addFailure(self, test, err):
print("\n<FAILED::>Test Failed")
print("\n<LOG:ESC:Failure>" + esc(''.join(traceback.format_exception_only(err[0], err[1]))))
super().addFailure(test, err)

# from unittest/result.py
def _exc_info_to_string(self, err, test):
exctype, value, tb = err
# Skip test runner traceback levels
while tb and self._is_relevant_tb_level(tb):
tb = tb.tb_next
if exctype is test.failureException:
length = self._count_relevant_tb_levels(tb) # Skip assert*() traceback levels
else:
length = None
return ''.join(traceback.format_tb(tb, limit=length))

def _is_relevant_tb_level(self, tb):
return '__unittest' in tb.tb_frame.f_globals

def _count_relevant_tb_levels(self, tb):
length = 0
while tb and not self._is_relevant_tb_level(tb):
length += 1
tb = tb.tb_next
return length

def esc(s):
return s.replace("\n", "<:LF:>")
27 changes: 24 additions & 3 deletions frameworks/ruby/sql/csv_importer.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
require 'csv'
require 'chronic'
require 'open-uri'

# data importer utility
class CsvImporter
attr_reader :fields, :csv, :table, :limit, :random

def initialize(file, table, fields: {}, limit: 500, random: false)
@csv = CSV.read(file)
# make it possible to load CSV files from either web or file system
@csv = if (file =~ /^https?:\//i) == 0
CSV.parse(open(file).read)
else
CSV.read(file)
end

@table = table
@fields = fields
@limit = limit
Expand All @@ -17,8 +24,22 @@ def create_schema
importer = self
DB.create_table @table do
importer.csv.first.each do |field|
if importer.fields[field]
column field, importer.fields[field]
if schema_type = importer.fields[field]
case schema_type
when :primary_key
primary_key field
when Array
case schema_type.first
when :primary_key
primary_key field, schema_type.last || {}
when :foreign_key
foreign_key field, schema_type[1], schema_type[2] || {}
end
else
column field, schema_type
end
elsif field == 'id'
primary_key :id
else
String field
end
Expand Down
2 changes: 1 addition & 1 deletion lib/runners/objc.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ function prepareUnitKit(opts) {
}
`;

codeWriteSync('objc', getCode(opts), opts.dir, 'solution.m');
codeWriteSync('objc', opts.solution, opts.dir, 'solution.m');
if (opts.setup) codeWriteSync('objc', opts.setup, opts.dir, 'setup.m');
const fixtureFile = codeWriteSync('objc', fixture, opts.dir, 'fixture.m');
const mainFile = codeWriteSync('objc', main, opts.dir, 'main.m');
Expand Down
66 changes: 63 additions & 3 deletions lib/runners/python.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
"use strict";

const writeFileSync = require('../utils/write-file-sync');

module.exports = {
solutionOnly(opts, runCode) {
runVersion(opts, [opts.setup, opts.solution].join("\n"), runCode);
},
testIntegration(opts, runCode) {
if (isNoConcat(opts)) return python3unittest(opts, runCode);
var code;
switch (opts.testFramework) {
case 'cw':
case 'cw-2':
code = opts.projectMode ? cw2Project(opts) : cw2Code(opts);
break;
case 'unittest':
// TODO: support projectMode for unittest, which should require
// improving unittest support so that a specific test case called Test doesn't need
// to be used
// TODO: support projectMode for unittest, which should require
// improving unittest support so that a specific test case called Test doesn't need
// to be used
code = unittestCode(opts);
break;
default:
Expand All @@ -23,6 +26,7 @@ module.exports = {
runVersion(opts, code, runCode);
},
sanitizeStdErr(opts, err) {
if (isNoConcat(opts)) return err;
// get rid of some of the noisy content. We remove line numbers since
// they don't match up to what the user sees and will only confuse them.
return err
Expand Down Expand Up @@ -123,3 +127,59 @@ print("<DESCRIBE::>Tests")
unittest.TestLoader().loadTestsFromTestCase(Test).run(reload(__import__('unittestwrapper')).CwTestResult())
print("<COMPLETEDIN::>")
`;

// Returns true if running tests without concatenation is possible.
function isNoConcat(opts) {
return opts.testFramework === 'unittest' && isPython3(opts);
}

// .
// |-- setup.py
// |-- solution.py
// `-- test
// |-- __init__.py
// |-- __main__.py
// `-- test_solution.py
// inspired by http://stackoverflow.com/a/27630375
//
// for backward compatibility:
// - prepend `import unittest` to fixture if missing
// - prepend `from solution import *` to fixture to simulate concatenation
// - prepend `from setup import *` to solution to simulate concatenation
function python3unittest(opts, runCode) {
let solution = opts.solution;
if (opts.setup) {
writeFileSync(opts.dir, 'setup.py', opts.setup);
if (!/^\s*import setup\s*$/m.test(solution) && !/^\s*from setup\s+/m.test(solution)) {
solution = 'from setup import *\n' + solution;
}
}
writeFileSync(opts.dir, 'solution.py', solution);
let fixture = opts.fixture;
if (!/^\s*import\s+unittest/m.test(fixture)) fixture = 'import unittest\n' + fixture;
if (!/^\s*import solution\s*$/m.test(fixture) && !/^\s*from solution\s+/m.test(fixture)) {
fixture = 'from solution import *\n' + fixture;
}
writeFileSync(opts.dir+'/test', 'test_solution.py', fixture);
writeFileSync(opts.dir+'/test', '__init__.py', '');
writeFileSync(opts.dir+'/test', '__main__.py', [
'import unittest',
'from codewars import CodewarsTestRunner',
'',
'def load_tests(loader, tests, pattern):',
' return loader.discover(".")',
'',
'unittest.main(testRunner=CodewarsTestRunner())',
'',
].join('\n'));
runCode({
name: pythonCmd(opts),
args: ['test'],
options: {
cwd: opts.dir,
env: Object.assign({}, process.env, {
PYTHONPATH: `/runner/frameworks/python:${process.env.PYTHONPATH}`
}),
}
});
}
73 changes: 73 additions & 0 deletions test/runners/objc_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,79 @@ describe('objc runner', function() {
done();
});
});

it('should support setup code', function(done) {
// https://github.com/Codewars/codewars.com/issues/1221
runner.run({
language: 'objc',
testFramework: 'unitkit',
setup: `
#import <Foundation/Foundation.h>
@interface Node: NSObject
{
int data;
Node *next;
}
@property (readonly) int data;
@property (readonly) Node *next;
- (id)initWithData: (int)d andNext: (Node *)n;
- (id)initWithData: (int)d;
+ (Node *)nodeWithData: (int)d andNext: (Node *)n;
+ (Node *)nodeWithData: (int)d;
@end
@implementation Node
@synthesize data;
@synthesize next;
- (id)initWithData: (int)d andNext: (Node *)n
{
data = d;
next = n;
return self;
}
- (id)initWithData: (int)d
{
data = d;
next = NULL;
return self;
}
+ (Node *)nodeWithData: (int)d andNext: (Node *)n
{
return [[Node alloc] initWithData: d andNext: n];
}
+ (Node *)nodeWithData: (int)d
{
return [[Node alloc] initWithData: d];
}
@end
`,
solution: `
#import <Foundation/Foundation.h>
NSString *stringify(Node *list) {
// TODO: Return a string representation of the list passed in
return @"";
}
`,
fixture: `
@implementation TestSuite
- (void)testNULL
{
UKStringsEqual(@"", stringify(NULL));
}
- (void)testSingle
{
UKStringsEqual(@"1", stringify([Node nodeWithData: 1]));
}
@end
`,
}, function(buffer) {
expect(buffer.stdout).to.contain('<PASSED::>');
expect(buffer.stdout).to.contain('<FAILED::>');
done();
});
});
});

describe('CW', function() {
Expand Down
Loading

0 comments on commit 9a9e10c

Please sign in to comment.