Kumite (ko͞omiˌtā) is the practice of taking techniques learned from Kata and applying them through the act of freestyle sparring.
You can create a new kumite by providing some initial code and optionally some test cases. From there other warriors can spar with you, by enhancing, refactoring and translating your code. There is no limit to how many warriors you can spar with.
A great use for kumite is to begin an idea for a kata as one. You can collaborate with other code warriors until you have it right, then you can convert it to a kata.
This shows a piece of test code in Python that is improved over the default cw-2
(and consistent with other languages' test frameworks) in the following aspects:
Initial release (v1.0)
- Utilize the
with
-block to support proper indentation ofdescribe
andit
blocks in the code - Properly close
describe
andit
blocks in the test output - Print the running times of
describe
andit
blocks - Make testing functions non-blocking
v1.1
- Provide a way to log Unicode strings for users (does not work for test framework)
Run the tests and see how the test output looks like.
def fibonacci(n):
if n <= 1: return 1
if n > 35: raise RuntimeError('Too large input')
return fibonacci(n-1) + fibonacci(n-2)
'''
Fix for the dreaded Unicode Trap (works in py3+)
This does not fix the test outputs, so some revision in cw-2 is needed
'''
from io import StringIO
import sys
_print = print
def _escape(s): return s.encode('ascii', 'xmlcharrefreplace').decode('ascii')
def print(*args, sep=' ', end='\n', file=sys.stdout):
sio = StringIO()
_print(*args, sep=sep, end=end, file=sio)
_print(_escape(sio.getvalue()), file=file)
sio.close()
print('\uac00 \ub098 \ub2e4 <\'">\\')
'''
Defining `describe` and `it` properly
'''
from timeit import default_timer as timer
from traceback import format_exception
def timed_block_wrapper(func):
class _wrapper(object):
def __init__(self, name):
self.name = name
self.func = func
self.timer = None
def __enter__(self):
self.func(self.name)
self.timer = timer()
def __exit__(self, typ, val, traceback):
if traceback:
test.expect(False, 'Unexpected exception raised')
tb_str = ''.join(format_exception(typ, val, traceback)).replace('\n', '<:LF:>')
print('<ERROR::>{}'.format(tb_str))
print('<COMPLETEDIN::>{}'.format(round((timer() - self.timer) * 1000, 2)))
return True
return _wrapper
Test.describe = timed_block_wrapper(Test.describe)
Test.it = timed_block_wrapper(Test.it)
'''
Non-blocking test failures
There are only four testing functions provided by CW (expect, assert_equals, assert_not_equals, expect_error),
two of which are blocking functions (i.e. stops execution on failure).
If you write customized test functions, you don't need this fix as long as you use Test.expect and provide helpful messages.
'''
AssertException = __import__('cw-2').AssertException
def test_wrapper(func):
def wrapped(*args, **kwargs):
try: func(*args, **kwargs)
except AssertException: pass
return wrapped
Test.assert_equals = test_wrapper(Test.assert_equals)
Test.assert_not_equals = test_wrapper(Test.assert_not_equals)
'''
Sample test fixture
'''
with Test.describe('Unicode'):
with Test.it('Simple'):
Test.assert_equals('\uac00 \ub098 \ub2e4', 'a b c')
with Test.describe('Fibonacci'):
with Test.it('Simple'):
Test.assert_equals(fibonacci(1), 2)
Test.assert_not_equals(fibonacci(1), 2)
Test.assert_not_equals(fibonacci(1), 1)
Test.assert_equals(fibonacci(5), 8)
Test.assert_equals(fibonacci(10), 89)
with Test.it('Higher'):
Test.assert_equals(fibonacci(15), 987)
Test.assert_equals(fibonacci(20), 10946)
Test.assert_equals(fibonacci(30), 1346269)
with Test.it('Extreme'):
Test.assert_equals(fibonacci(32), 3524578)
Test.expect_error('Some message', lambda: fibonacci(36))
Test.expect_error('Some other message', lambda: fibonacci(1))
Test.assert_equals(fibonacci(36), 0)
A simple FizzBuzz implementation, to try out Kumites.
Take a positive integer as input, and output:
- "Fizz" if the number is divisible by three
- "Buzz" if the number is divisible by five
- "FizzBuzz" if the number is divisible by three and five
- otherwise, just the number (as a string)
using System;
namespace Solution {
class FizzBuzz {
public static string convert(int input){
if (input % 3 == 0 && input % 5 == 0) {
return "FizzBuzz";
}
if (input % 3 == 0) {
return "Fizz";
}
if (input % 5 == 0) {
return "Buzz";
}
return input.ToString();
}
}
}
namespace Solution {
using NUnit.Framework;
using System;
// TODO: Replace examples and use TDD development by writing your own tests
[TestFixture]
public class SolutionTest
{
[Test]
public void NotDivisibleByThreeOrFive()
{
Assert.That(FizzBuzz.convert(1), Is.EqualTo("1"));
Assert.That(FizzBuzz.convert(7), Is.EqualTo("7"));
}
[Test]
public void DivisibleByThree()
{
Assert.That(FizzBuzz.convert(3), Is.EqualTo("Fizz"));
Assert.That(FizzBuzz.convert(12), Is.EqualTo("Fizz"));
}
[Test]
public void DivisibleByFive()
{
Assert.That(FizzBuzz.convert(5), Is.EqualTo("Buzz"));
Assert.That(FizzBuzz.convert(95), Is.EqualTo("Buzz"));
}
[Test]
public void DivisibleByThreeAndFive()
{
Assert.That(FizzBuzz.convert(15), Is.EqualTo("FizzBuzz"));
Assert.That(FizzBuzz.convert(90), Is.EqualTo("FizzBuzz"));
}
}
}
Outline
This is a proposal for CodeWars test framework for Python to improve it in many ways (and be more consistent with other languages' frameworks).
Unlike my previous Kumite, this one is designed to completely replace cw-2.py
in the runner repo.
Changes / Improvements
Individual Testing / Logging Functions
- Make testing functions non-blocking
- Change the expression inside
assert_not_equals
so that it can prevent operator injection hacks - Provide a way to log and test Unicode strings without Unicode-related error
- Provide a utility for timeout
- Provide
pass
,fail
andassert_approx_equals
Describe / It
- Build the decorator version of
describe
andit
, so the text fixture may look like this (and the decorator itself runs the code, so it doesn't need a separate runner function):
@describe('describe-text')
def describe1():
@it('it-text', before=f1, after=f2)
def it1():
# some test function
@it('it-text')
def it2():
# some test function
- Properly close
describe
andit
blocks in the test output - Print the running times of
describe
andit
blocks - Provide
before
andafter
fordescribe
andit
#from __future__ import print_function
class AssertException(Exception):
pass
'''Fix the dreaded Unicode Error Trap'''
_print = print
def print(*args, sep=' ', end='\n'):
from io import StringIO
def _escape(s): return s.encode('ascii', 'xmlcharrefreplace').decode('ascii')
sio = StringIO()
_print(*args, sep=sep, end=end, file=sio)
_print(_escape(sio.getvalue()))
sio.close()
def format_message(message):
return message.replace("\n", "<:LF:>")
def expect(passed=None, message=None, allow_raise=False):
if passed: print("\n<PASSED::>Test Passed")
else:
message = message or "Value is not what was expected"
print("\n<FAILED::>{0}".format(message))
if allow_raise: raise AssertException(message)
'''Fix the blocking asserts to non-blocking'''
def assert_equals(actual, expected, message=None, allow_raise=False):
equals_msg = "{0} should equal {1}".format(repr(actual), repr(expected))
if message is None: message = equals_msg
else: message += ": " + equals_msg
expect(actual == expected, message, allow_raise)
'''
Fix the blocking asserts to non-blocking
Also change the expected formula from `actual != expected` to `not (actual == expected)`
so that using this assertion can prevent the `==` / `!=` injection hack
'''
def assert_not_equals(actual, expected, message=None, allow_raise=False):
equals_msg = "{0} should not equal {1}".format(repr(actual), repr(expected))
if message is None: message = equals_msg
else: message += ": " + equals_msg
expect(not (actual == expected), message, allow_raise)
def expect_error(message, function):
passed = False
try: function()
except: passed = True
expect(passed, message)
'''Additional test functions: pass, fail, and assert_approx_equals'''
def pass_(): expect(True)
def fail(message): expect(False, message)
def assert_approx_equals(actual, expected, margin=1e-9, message=None, allow_raise=False):
equals_msg = "{0} should be close to {1} with absolute or relative margin of {2}".format(
repr(actual), repr(expected), repr(margin))
if message is None: message = equals_msg
else: message += ": " + equals_msg
div = max(abs(actual), abs(expected), 1)
expect(abs((actual - expected) / div) < margin, message, allow_raise)
def display(type, message, label="", mode=""):
print("\n<{0}:{1}:{2}>{3}".format(type.upper(), mode.upper(), label, format_message(message)))
'''
Modern-Style Describe & It
Usage:
@describe('describe text')
def describe1():
@it('it text')
def it1():
# some test cases...
'''
def _timed_block_factory(opening_text):
from timeit import default_timer as timer
from traceback import format_exception
from sys import exc_info
def _timed_block_decorator(s, before=None, after=None):
print('<{}::>{}'.format(opening_text, s))
def wrapper(func):
if callable(before): before()
time = timer()
try: func()
except:
fail('Unexpected exception raised')
tb_str = ''.join(format_exception(*exc_info())).replace('\n', '<:LF:>')
print('<ERROR::>' + tb_str)
print('<COMPLETEDIN::>{}'.format(round((timer() - time) * 1000, 2)))
if callable(after): after()
return wrapper
return _timed_block_decorator
describe = _timed_block_factory('DESCRIBE')
it = _timed_block_factory('IT')
'''
Timeout utility
Usage:
with run_with_timeout(func, tuple_of_args, timeout_in_seconds) as run:
Test.assert_equals(run.get(), expected_value)
Note: Timeout value can be a float.
'''
class run_with_timeout(object):
def __init__(self, func, inputs, sec):
from multiprocessing import Process, Queue
def timeout_wrapper(func, inputs, q):
q.put(func(*inputs))
self.sec = sec
self.q = Queue()
self.p = Process(target=timeout_wrapper, args=(func, inputs, self.q))
self.result = None
def __enter__(self):
self.p.start()
return self
def get(self):
if self.result is None: self.result = self.q.get(timeout=self.sec)
return self.result
def __exit__(self, typ, val, traceback):
self.q.close()
self.p.terminate()
self.p.join()
if traceback: fail('Exceeded time limit of {:.3f} seconds'.format(self.sec))
return True
'''Old-style Fixture'''
describe('Old-style Describe')
it('Old-style It')
assert_equals(0, 0)
assert_equals(0, 1)
print('<COMPLETEDIN::>')
it('Old-style It 2')
assert_equals('a', 'a')
assert_equals('a', 'b')
print('<COMPLETEDIN::>')
print('<COMPLETEDIN::>')
'''Sample Fixture #1'''
@describe('Sample Fixture #1')
def sample_describe_1():
@it('Sample Testcase #1-1')
def sample_it_1():
assert_equals(0, 0)
assert_equals(0, 1)
assert_not_equals(0, 2)
pass_()
fail('This should fail')
@it('Sample Testcase #1-2')
def sample_it_2():
expect_error('ZeroDivisionError', lambda: 0 / 0)
assert_equals(0, 0 / 0)
assert_equals(1, 1, 'This is not run due to exception')
@it('Sample Testcase #1-3')
def sample_it_3():
assert_equals('abc', 'abc')
# source code doesn't support utf-8 chars, but you can at least log and test unicode
assert_equals('\uac00 \ub098 \ub2e4', '\uac00 \ub098 \ub2e4')
print('\uac00 \ub098 \ub2e4')
assert_equals('\uac00 \ub098 \ub2e4', 'a b c')
'''Sample Fixture #2: Featuring Before and After'''
@describe('Sample Fixture #2')
def sample_describe_2():
a = {0}
def before():
a.add(len(a))
@it('Sample Testcase #2-1', before=before, after=before)
def sample_it_1():
assert_equals(a, {0, 1})
@it('Sample Testcase #2-2')
def sample_it_2():
assert_equals(a, {0, 1, 2})
'''Sample Fixture #3: Featuring Timeout'''
@describe('Sample Fixture #3')
def sample_describe_3():
def wait_count(n):
for _ in range(n): pass
return n
@it('Sample Testcase #3-1')
def sample_it_1():
with run_with_timeout(wait_count, (100,), 0.01) as run:
assert_equals(run.get(), 100)
@it('Sample Testcase #3-2')
def sample_it_2():
with run_with_timeout(wait_count, (10 ** 10,), 0.01) as run:
assert_equals(run.get(), 10 ** 10)
'''Sample Fixture #4: Featuring assert_approx_equals'''
@describe('Sample Fixture #4')
def sample_describe_4():
@it('Sample Testcase #4-1')
def sample_it_1():
assert_approx_equals(1, 1 + 1e-10, 1e-9)
assert_approx_equals(1, 1 + 1e-7, 1e-9)
assert_approx_equals(-1, -1 - 1e-10, 1e-9)
assert_approx_equals(-1, -1 - 1e-7, 1e-9)
@it('Sample Testcase #4-2')
def sample_it_2():
assert_approx_equals(0, 1e-10, 1e-9)
assert_approx_equals(0, 1e-7, 1e-9)
assert_approx_equals(0, -1e-10, 1e-9)
assert_approx_equals(0, -1e-7, 1e-9)
Input an int array and returns the average of the numbers in it.
public class Average {
public static int averageFinder(int[] arr) {
int total = 0;
for(int num: arr){
total += num;
}
int result = total / arr.length;
return result;
}
}
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;
// TODO: Replace examples and use TDD development by writing your own tests
public class SolutionTest {
@Test
public void testSomething() {
Average av = new Average();
int arr1[] = {96, 98};
assertEquals(97, av.averageFinder(arr1));
int arr2[] = {94, 96, 98};
assertEquals(96, av.averageFinder(arr2));
}
}
import java.util.*;
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
}
class BST {
public static boolean search(Node root, int key) {
if(root == null) {
return false;
}
while(root != null) {
if(root.value == key) {
return true;
}
if(root.value > key) {
root = root.left;
} else if(root.value < key) {
root = root.right;
}
}
return false;
}
}
import org.junit.*;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;
public class SolutionTest {
Node root;
@Before
public void setUp() {
root = new Node(10);
Node B = new Node(5);
Node C = new Node(15);
Node D = new Node(4);
Node E = new Node(6);
Node F = new Node(12);
Node G = new Node(17);
root.left = B;
root.right = C;
B.left = D;
B.right = E;
C.left = F;
C.right = G;
}
@Test
public void testSomething() {
assertEquals(BST.search(root, 4), true);
}
@Test
public void testSomething2() {
assertEquals(BST.search(root, 16), false);
}
@Test
public void testSomething3() {
assertEquals(BST.search(root, 12), true);
}
@Test
public void testSomething4() {
assertEquals(BST.search(root, 17), true);
}
@Test
public void testSomething5() {
assertEquals(BST.search(root, 8), false);
}
}
Output numbers from 1 to x. If the number is divisible by 3, replace it with “Fizz”. If it is divisible by 5, replace it with “Buzz”. If it is divisible by 3 and 5 replace it with “FizzBuzz”.
(ns fizzbuzz.core)
(defn divisible-by? [divisor number]
(zero? (mod number divisor)))
(defn fizzbuzz [x]
(map #(cond
(divisible-by? 15 %) "FizzBuzz"
(divisible-by? 5 %) "Buzz"
(divisible-by? 3 %) "Fizz"
:else %)
(range 1 (inc x))))
(ns fizzbuzz.core-test
(:require [clojure.test :refer :all]
[fizzbuzz.core :refer :all]))
(deftest a-test1
(testing "Test 1"
(is (= (fizzbuzz 16) [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz", 16]))))
const flatten = arr =>
arr.reduce((acc, item) => Array.isArray(item) ? [...acc, ...flatten(item)] : [...acc, item], []);
const flatten = arr =>
arr.reduce((acc, item) => Array.isArray(item) ? [...acc, ...flatten(item)] : [...acc, item], []);
describe("Test cases", function() {
it("[1, 2, [3, 5], [[4, 3], 2]]", function() {
Test.assertSimilar(flatten([1, 2, [3, 5], [[4, 3], 2]]), [1, 2, 3, 5, 4, 3, 2]);
});
it("[[1, [5], [], [[-3, 'hi']]], 'string', 10, [[[5]]]]", function() {
Test.assertSimilar(flatten([[1, [5], [], [[-3, 'hi']]], 'string', 10, [[[5]]]]), [1, 5, -3, 'hi', 'string', 10, 5]);
});
});
Given any matrix, NxN or MxN we should be able to extract the inner matrix.
For example:
MxN [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] -> [[6, 7]]
NxN [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] -> [[6, 7], [10, 11]]
innerMatrix = array => array
.slice(1, array.length - 1)
.map(row => row.slice(1, array[0].length - 1));
describe("Basic Tests", function(){
it("It should works for basic tests.", function(){
Test.assertEquals(innerMatrix([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]).join('.').toString(),'6,7')
Test.assertEquals(innerMatrix([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]).join('.').toString(),'6,7.10,11')
Test.assertEquals(innerMatrix([[1, 2], [5, 6]]).join('.').toString(),'')
Test.assertEquals(innerMatrix(
[[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30]]).join('.').toString()
,'7,8,9.12,13,14.17,18,19.22,23,24')
})})
BRAINFUCK VIZUALISER
How to use it:
Debugging commands usable in the BF code:
'?' char in the code to choose the debugging points.
You cnan name the check points with r'\w+' characters after the ?
'!' char to switch on/off the full debugging (print at the execution of each segment)
Other global switches available:
ALL: vizualisation at each step of the code (each segment). Only when you're desperate...
DEACTIVATE: force the deactivation of the vizualisation whatever is found in the code or the other switches are
CHAR_MODE: if True, the tape will display ascii chars instead of numbers (Note: unprintable chars won't show up...)
LIMITER: interrupt the executions after this number of printing. The count is reseted for each test
Here is the kind of output you get, with the code joint (note: I messed up the code of a previously completed kata):
Input: 3
?START
[ 0, 1, 51] tape
[ 0, 0, 1] p
out = ''
?REMOVE_SOME
[ 0, 1, 13, 0] tape
[ 0, 0, 1, 0] p
out = ''
?ISNOTDOT
[ 0, 1, 51, 0, 1] tape
[ 0, 0, 0, 0, 1] p
out = ''
?GET_DECIMAL
[ 0, 1, 51, 0, 0, 0] tape
[ 0, 0, 0, 0, 0, 1] p
out = ''
Input: 3
3 should be 3
SUCCESS
---
Input: 1.5
?START
[ 0, 1, 49] tape
[ 0, 0, 1] p
out = ''
?REMOVE_SOME
[ 0, 1, 11, 0] tape
[ 0, 0, 1, 0] p
out = ''
?ISNOTDOT
[ 0, 1, 49, 0, 1] tape
[ 0, 0, 0, 0, 1] p
out = ''
?START
[ 0, 1, 49, 46, 0] tape
[ 0, 0, 0, 1, 0] p
out = ''
?REMOVE_SOME
[ 0, 1, 49, 8, 0] tape
[ 0, 0, 0, 1, 0] p
out = ''
?ISNOTDOT
[ 0, 1, 49, 46, 0, 1] tape
[ 0, 0, 0, 0, 0, 1] p
out = ''
?START
[ 0, 1, 49, 46, 53, 0] tape
[ 0, 0, 0, 0, 1, 0] p
out = ''
?REMOVE_SOME
[ 0, 1, 49, 46, 15, 0] tape
[ 0, 0, 0, 0, 1, 0] p
out = ''
?ISNOTDOT
[ 0, 1, 49, 46, 53, 0, 1] tape
[ 0, 0, 0, 0, 0, 0, 1] p
out = ''
?GET_DECIMAL
[ 0, 1, 49, 46, 53, 0, 0, 0] tape
[ 0, 0, 0, 0, 0, 0, 0, 1] p
out = ''
Input: 1.5
1.5 should be 2
STDERR:
Traceback:
in <module>
AssertionError
"""
Created on Mon Oct 23 21:59:51 2017
BrainFuck tape, pointer & output vizualizer
@author: Blind4Basics - CodeWars
"""
# -----------------------------------------------------------------
# Debugging commands usable in the BF code:
#
# '?' char in the code to choose the debugging points.
# You cnan name the check points with r'\w+' characters after the ?
# '!' char to switch on/off the full debugging (print at the execution of each segment)
#
#
# Other global switches available:
#
# ALL: vizualisation at each step of the code (each segment). Only when you're desperate...
# DEACTIVATE: force the deactivation of the vizualisation whatever is found in the code or the other switches are
# CHAR_MODE: if True, the tape will display ascii chars instead of numbers (Note: unprintable chars won't show up...)
# LIMITER: interrupt the executions after this number of printing. The count is reseted for each test
#
# -----------------------------------------------------------------
code = """ # not working example
[
tape: _ S digits _ REF DEC S
]
>+
>,
[?START
>++++[<---------->-]<++
?REMOVE_SOME
[
>++++[<++++++++++>-]<--
>>+<
]
<[<]>[>]>
?ISNOTDOT
[-<,>]<
]
>>,
?GET_DECIMAL
[
>++++[<-------->-]
+<<++++
?
[->[->[>]]<<]
?MINUS4
>[[-]<+>]
?LAST
]
<<<[<]>>[.>]
"""
#------------------------------------------------------------
# Test cases:
#
# 'inputs' and corresponding 'expected' values
# EOF char automatically added at the end of each input
#------------------------------------------------------------
inputs = ["3", "1.5", "101", "101.9", "101.2"]
exp = ["3", "2", "101", "102", "101"]
""" GLOBAL SWITCHES """
ALL = False
DEACTIVATE = False
CHAR_MODE = False
LIMITER = 50
import re
def brainFuckInterpreter(code, prog):
def updateVizu(cmdSegment=''):
def formatLst(lst, charMod=False): # Formater: align the cells of the tape and the list for the pointer
formStr = "{: >" + str(max(map(len, map(str, data)), default=1)) + "}"
return "[{}]".format(', '.join(formStr.format(chr(v) if charMod else v) for v in lst))
if DEACTIVATE: return
countDisplay[0] += 1 # Update the number of display already done (cf. LIMITER)
vizu[-1][lastP[0]] = 0 # Erase the previous position of the pointer
vizu[-1][p] = 1 # Place the pointer at the current position
lastP[0] = p # archive the current position of the pointer
vizu[0] = c[0] # archive the current command
out = ''.join(output)
cmd,tape,point = vizu
print( "\n\n{}{} tape\n{} p\nout = '{}'".format(cmdSegment and cmdSegment+"\n",
formatLst(tape, CHAR_MODE),
formatLst(point),
out) )
if LIMITER >= 0 and LIMITER == countDisplay[0]: raise Exception("Too much printing: LIMITER = {}".format(LIMITER))
def tapeLenUpdater(): # Make the tape length consistent with the actual position of the pointer (even if no value yet in the cells)
if p >= len(data):
data.extend( [0] * (p-len(data)+1) )
vizu[-1].extend( [0] * (len(data)-len(vizu[-1])) )
def getNextInput(): # Simulate getting u'0000' when trying to get an input char after their exhaustion
try:
return ord(next(prog))
except StopIteration:
return 0
p, lastP, i = 0, [0], 0 # p = pointer / lastP = previous P position (mutated) / i = segment of code index
data = [0] # Tape initialization
SWITCH, countDisplay = False, [0] # SWITCH: control for the "!" cmd swtich / countDisplay = control for LIMITER (as list to mutate it from a subroutine)
output, vizu = [], ['', data, [0]] # vizu: [cmd, tape, pointer list]
prog = iter(prog)
code = re.findall(r'\++|<+|>+|-+|[,.[\]]|\?\w*|!', code) # Make the executions more compact by using only segments of identical commands (=> '++++', '<<<', '[', '-', ']', check points with identifiers...)
while 0 <= i < len(code):
c = code[i]
if False: print(c, data, p) # activate manually. Only for debugging of the vizualiser itself...
if c[0] == '+': data[p] = (data[p] + len(c)) % 256
elif c[0] == '-': data[p] = (data[p] - len(c)) % 256
elif c[0] == '>': p += len(c) ; tapeLenUpdater()
elif c[0] == '<': p -= len(c) ; tapeLenUpdater()
elif c[0] == '.': output.append(chr(data[p]))
elif c[0] == ',': data[p] = getNextInput()
elif c[0] == '[':
if not data[p]:
depth = 1
while depth > 0:
i += 1
c = code[i]
if c == '[': depth += 1
elif c== ']': depth -= 1
elif c == ']':
if data[p]:
depth = 1
while depth > 0:
i -= 1
c = code[i]
if c == ']': depth += 1
elif c == '[': depth -= 1
# Vizualisation commands/executions
#--------------------
elif c[0] == '?': updateVizu(c) # check point found
if ALL or SWITCH and c[0] != "?": updateVizu(c) # Vizualisation for swithes (avoid double printing for check points)
if c[0] == '!': SWITCH = not SWITCH # Update '!' swtich state
#--------------------
i += 1
return ''.join(output)
#--------------------
# LAUNCH THE TESTS
#--------------------
EOF = chr(0)
for p,e in zip(inputs,exp):
print("Input: ", p)
act = brainFuckInterpreter(code, p+EOF)
print("Input: ", p) # remainder of the input
print(act, " should be ", e) # print actual/expected before assertion
assert act == e
print("SUCCESS\n---\n")
In this kata you should find BB-tags (bulletin board tags) in given string.
BB-tags look like:
[B]Some content[/B],
where [B] - opening tag and [/B] - closing tag.
Name of tags also can be lowercase:
[url]Some content[/url]
And BB-tags can be nested into each other, for example:
[url][b][size=5][color=blue]Some content[/color][/size][/b][/url]
If there is nested BB-tags, you should return only the outer tag with all it's content (with another tags into it).
function test(str) {
return (str.match(/\[([a-zA-Z]+)](.*)\[\/\1]/g)).join('');
}
describe("Finding 'BB'-tags in text", function(){
it("Testing for singular pair of tags", function(){
Test.assertEquals(test("Так записывается ссылка: [url]http://ya.ru[/url]"),"[url]http://ya.ru[/url]");
});
it("Testing for two pair of tags", function(){
Test.assertEquals(test("Ссылка, текст которой выделен жирным: [url][b]http://ya.ru[/b][/url]"), "[url][b]http://ya.ru[/b][/url]");
});
it("Testing for empty content of tags", function(){
Test.assertEquals(test("Теги без содержимого: [url][/url]"), "[url][/url]");
});
it("Testing for empty content of several tags", function(){
Test.assertEquals(test("Выделенная жирным цитата со ссылкой на источник(которого нет): [url][b][quote][/quote][/b][/url]"), "[url][b][quote][/quote][/b][/url]");
});
it("Testing for a lot of nested tags", function(){
Test.assertEquals(test("It should work for a lot of different nested tags: [url][b][size=5][color=blue]Some content[/color][/size][/b][/url]"), "[url][b][size=5][color=blue]Some content[/color][/size][/b][/url]");
});
});