Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on May 27, 2021. It is now read-only.

Commit 0bfd721

Browse files
author
sannithibalaji
authored
Merge pull request #24 from jbuddha/master
code runner and unit tests for running java, python, c source code
2 parents 3aa4228 + 90d3f5a commit 0bfd721

16 files changed

+441
-4
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
openrank/db.sqlite3
22
openrank/*/migrations
33
openrank/*/__pycache__/
4+
.cache
5+
.cache/
6+
framework/__pycache__/
7+
tests/.cache/
8+
tests/__pycache__/
9+
tests/framework/.cache/
10+
tests/framework/__pycache__/

.travis.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
language: python
2+
3+
python:
4+
- 3.6
5+
- nightly
6+
7+
install:
8+
- pip install .
9+
- pip install -r requirements.txt
10+
11+
script:
12+
- pytest

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ OpenRank is a free and open source alternative for websites like HackerRank, Hac
22

33
Join the disucssion chatroom for this project on Discord : https://discord.gg/c7pU8Rw
44

5+
[![Build Status](https://travis-ci.org/jbuddha/OpenRank.svg?branch=master)](https://travis-ci.org/jbuddha/OpenRank)
6+
57
## Running :
68

79
You can run the apiserver by using the following command
@@ -18,6 +20,12 @@ To run frontend use the following commands in sequence
1820

1921
open http://localhost:8081/ once the server is started
2022

23+
## Unit tests :
24+
25+
You can run the unit tests by running following command in project folder. Make sure you install pytest module first.
26+
27+
`python3 -m pytest`
28+
2129
## Resources :
2230
Vue.js
2331
- [Vue.js 2.0 In 60 Minutes](https://www.youtube.com/watch?v=z6hQqgvGI4Y)

__init__.py

Whitespace-only changes.

framework/Classes.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from enum import Enum
2+
3+
4+
class Status(Enum):
5+
IN_PROGRESS = 0
6+
OK = 1
7+
COMPILE_ERROR = 2
8+
RUNTIME_ERROR = 3
9+
TIMEOUT = 3
10+
ENV_CRASH = 4
11+
12+
13+
class ProgrammingLanguage(Enum):
14+
C = "C"
15+
CPP = "C++"
16+
JAVA8 = "Java 8"
17+
PYTHON2 = "Python 2"
18+
PYTHON = "Python 3"
19+
RUBY = "Ruby"
20+
JAVASCRIPT = "Node.js"
21+
22+
23+
class Submission:
24+
def __init__(self):
25+
self.source = ""
26+
self.programming_language = ""
27+
self.compile_command = []
28+
self.run_command = []
29+
self.test_cases_input = []
30+
31+
32+
class Testcase:
33+
def __init__(self):
34+
self.id = ""
35+
self.input = ""
36+
self.file = ""
37+
self.timeout = 2
38+
39+
40+
class Output:
41+
def __init__(self):
42+
self.test_case_id = ""
43+
self.memory = 0
44+
self.time = 0
45+
self.stdout = ""
46+
self.stderr = ""
47+
self.status = Status.IN_PROGRESS
48+
49+
def __repr__(self):
50+
return self.stdout + self.stderr
51+
52+
53+
54+

framework/runner.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import subprocess
2+
import os
3+
import uuid
4+
import shutil
5+
6+
from framework.Classes import Output, Status, Testcase
7+
8+
default_test_case = Testcase()
9+
default_test_case.timeout = 2
10+
default_test_case.id = "1"
11+
default_testcase_array = [default_test_case]
12+
13+
14+
def run(source, source_extension, compile_commands, run_command, test_cases=default_testcase_array):
15+
result = []
16+
current_directory = os.getcwd()
17+
temp_dir = uuid.uuid4().hex
18+
os.makedirs(temp_dir)
19+
os.chdir(temp_dir)
20+
21+
try:
22+
source_file_name = create_source_file(source, source_extension)
23+
out_compile = compile_source(compile_commands, source_file_name, result)
24+
execute_tests(run_command, test_cases, out_compile, result)
25+
except Exception as e:
26+
out_exception = Output()
27+
result.append(out_exception)
28+
out_exception.status = Status.ENV_CRASH
29+
out_exception.stderr = str(e)
30+
print(os.sys.exc_info())
31+
32+
os.chdir(current_directory)
33+
shutil.rmtree(temp_dir, True)
34+
35+
return result
36+
37+
38+
def execute_tests(run_command, test_cases, out_compile, result):
39+
if out_compile.status != Status.COMPILE_ERROR:
40+
for test_case in test_cases:
41+
out_test = Output()
42+
out_test.test_case_id = test_case.id
43+
44+
if run_command:
45+
completed = subprocess.run(run_command,
46+
stdout=subprocess.PIPE,
47+
stderr=subprocess.PIPE,
48+
input=test_case.input.encode('utf-8'),
49+
timeout=test_case.timeout)
50+
out_test.stdout = completed.stdout.decode('utf-8').rstrip()
51+
out_test.stderr = completed.stderr.decode('utf-8').rstrip()
52+
53+
if completed.returncode:
54+
out_test.status = Status.RUNTIME_ERROR
55+
else:
56+
out_test.status = Status.OK
57+
58+
result.append(out_test)
59+
60+
61+
def compile_source(compile_commands, source_file_name, result):
62+
out_compile = Output()
63+
if compile_commands:
64+
compile_commands.append(source_file_name)
65+
completed = subprocess.run(compile_commands,
66+
stdout=subprocess.PIPE,
67+
stderr=subprocess.PIPE)
68+
if completed.returncode:
69+
result.append(out_compile)
70+
out_compile.status = Status.COMPILE_ERROR
71+
out_compile.stdout = completed.stdout.decode('utf-8').rstrip()
72+
out_compile.stderr = completed.stderr.decode('utf-8').rstrip()
73+
else:
74+
out_compile.status = Status.OK
75+
76+
return out_compile
77+
78+
79+
def create_source_file(source, source_extension):
80+
source_file_name = "Source." + source_extension
81+
text_file = open(source_file_name, "w")
82+
text_file.write(source)
83+
text_file.close()
84+
return source_file_name
85+
86+

framework/test_data.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
from framework.Classes import Testcase
2+
3+
4+
tc1 = Testcase()
5+
tc1.id = "1"
6+
tc1.input = '23\n34'
7+
tc1.timeout = 1
8+
9+
tc2 = Testcase()
10+
tc2.id = "2"
11+
tc2.input = """21 34"""
12+
tc2.timeout = 1
13+
14+
java_source_code_with_input = """
15+
import java.util.*;
16+
17+
class Solution{
18+
public static void main(String... args) {
19+
Scanner scan = new Scanner(System.in);
20+
int sum = scan.nextInt() + scan.nextInt();
21+
System.out.println(sum);
22+
}
23+
}
24+
"""
25+
26+
java_source_code_with_no_input = """
27+
class Solution{
28+
public static void main(String... args) {
29+
System.out.println("Hello World");
30+
}
31+
}
32+
"""
33+
34+
java_source_code_with_exception = """
35+
class Solution{
36+
public static void main(String... args) {
37+
throw new RuntimeException();
38+
}
39+
}
40+
"""
41+
42+
java_source_code_with_compile_error = """
43+
class Solution{
44+
public static void main(String... args) {
45+
int a
46+
}
47+
}
48+
"""
49+
50+
python3_source_code_add_two_numbers = """
51+
# s = input()
52+
# print(s)
53+
# numbers = s.split()
54+
number1 = input()
55+
number2 = input()
56+
57+
sum = int(number1) + int(number2)
58+
print(sum)
59+
"""
60+
61+
python2_source_code_add_two_numbers = """
62+
number1 = raw_input()
63+
number2 = raw_input()
64+
65+
sum = int(number1) + int(number2)
66+
print sum
67+
"""
68+
69+
c_source_code_add_two_numbers = """
70+
#include<stdio.h>
71+
72+
int main() {
73+
int a, b, sum;
74+
75+
scanf("%d %d", &a, &b);
76+
77+
sum = a + b;
78+
79+
printf("%d", sum);
80+
81+
return(0);
82+
}
83+
"""
84+
85+
86+
c_source_code_add_two_numbers_compile_error = """
87+
#include<stdio.h>
88+
89+
int main() {
90+
int a, b, sum;
91+
92+
scanf("%d %d", &a, &b);
93+
94+
sum = a b;
95+
96+
printf("%d", sum);
97+
98+
return(0);
99+
}
100+
"""
101+
102+
cpp_source_code_add_two_numbers = """
103+
#include <iostream>
104+
using namespace std;
105+
106+
int main()
107+
{
108+
int firstNumber, secondNumber, sumOfTwoNumbers;
109+
110+
cin >> firstNumber >> secondNumber;
111+
112+
// sum of two numbers in stored in variable sumOfTwoNumbers
113+
sumOfTwoNumbers = firstNumber + secondNumber;
114+
115+
// Prints sum
116+
cout << sumOfTwoNumbers;
117+
118+
return 0;
119+
}"""
120+
121+
cs_source_code_add_two_numbers = """
122+
using System;
123+
124+
namespace OpenRank
125+
{
126+
class Program
127+
{
128+
static void Main(string[] args)
129+
{
130+
131+
int x;
132+
int y;
133+
int result;
134+
x = Convert.ToInt32(Console.ReadLine());
135+
y = Convert.ToInt32(Console.ReadLine());
136+
result = x + y;
137+
Console.Write(""+result);
138+
}
139+
}
140+
}"""

framework/test_runner_c.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from framework.Classes import Status
2+
from framework.runner import run
3+
from framework.test_data import tc1, c_source_code_add_two_numbers, c_source_code_add_two_numbers_compile_error
4+
5+
6+
def test_c_add_two_numbers_code():
7+
out = run(c_source_code_add_two_numbers, "c", ["gcc", "-o", "program"], ["./program"], [tc1])
8+
assert 1 == len(out)
9+
assert '57' == out[0].stdout
10+
assert Status.OK == out[0].status
11+
12+
13+
def test_c_add_two_numbers_code_compile_error():
14+
out = run(c_source_code_add_two_numbers_compile_error, "c", ["gcc", "-o", "program"], ["./program"], [tc1])
15+
assert 1 == len(out)
16+
assert ": error: expected" in out[0].stderr
17+
assert "sum = a b;" in out[0].stderr
18+
assert Status.COMPILE_ERROR == out[0].status

framework/test_runner_common.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from framework.Classes import Status
2+
from framework.runner import run
3+
from framework.test_data import java_source_code_with_input, tc1, tc2, java_source_code_with_no_input
4+
5+
6+
def test_with_no_input():
7+
out = run(java_source_code_with_no_input, "java", ["javac"], ["java", "Solution"])
8+
assert 1 == len(out), 'Only 1 output must exist'
9+
assert 'Hello World' == out[0].stdout
10+
assert Status.OK == out[0].status
11+
12+
13+
def test_two_inputs():
14+
out = run(java_source_code_with_input, "java", ["javac"], ["java", "Solution"], [tc1, tc2])
15+
assert 2 == len(out)
16+
assert '57' == out[0].stdout
17+
assert Status.OK == out[0].status
18+
assert '55' == out[1].stdout
19+
assert Status.OK == out[1].status
20+
21+
22+
def test_with_incorrect_compile_command():
23+
out = run(java_source_code_with_no_input, "java", ["javacxyz"], ["java", "Solution"])
24+
assert 1 == len(out), 'Only 1 output must exist'
25+
assert 'No such file or directory' in out[0].stderr
26+
assert Status.ENV_CRASH == out[0].status
27+
28+
29+
def test_with_incorrect_run_command():
30+
out = run(java_source_code_with_no_input, "java", ["javac"], ["javaxyz", "Solution"])
31+
assert 1 == len(out), 'Only 1 output must exist'
32+
assert 'No such file or directory' in out[0].stderr
33+
assert Status.ENV_CRASH == out[0].status

framework/test_runner_cpp.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import pytest
2+
from framework.Classes import Status
3+
from framework.runner import run
4+
from framework.test_data import tc1, cpp_source_code_add_two_numbers, c_source_code_add_two_numbers_compile_error
5+
6+
7+
def test_c_add_two_numbers_code():
8+
out = run(cpp_source_code_add_two_numbers, "cpp", ["g++", "-o", "program"], ["./program"], [tc1])
9+
assert 1 == len(out)
10+
assert '57' == out[0].stdout
11+
assert Status.OK == out[0].status
12+

0 commit comments

Comments
 (0)