# HG changeset patch # User Nattee Niparnan # Date 2019-10-07 08:56:18 # Node ID 4315e4a33c9c08a9d4013a94f6ff1aa1f8442b41 # Parent eb69d79cfbdd77df20b0b9218046f3e9540fa6a0 add submission test diff --git a/Gemfile.lock b/Gemfile.lock --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,6 +83,9 @@ rack-test (>= 0.6.3) regexp_parser (~> 1.5) xpath (~> 3.2) + capybara-console (0.0.4) + capybara + rails (>= 3.0) childprocess (1.0.1) rake (< 13.0) coffee-rails (4.2.2) @@ -296,6 +299,7 @@ bootstrap3-datetimepicker-rails byebug capybara (>= 2.15) + capybara-console coffee-rails dynamic_form fuzzy-string-match diff --git a/app/views/submissions/edit.html.haml b/app/views/submissions/edit.html.haml --- a/app/views/submissions/edit.html.haml +++ b/app/views/submissions/edit.html.haml @@ -46,10 +46,6 @@ - if @submission = render :partial => 'submission_short', :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id } - .row - .col-md-12 - %h2 Console - %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20} - if @submission .modal.fade#compiler{tabindex: -1,role: 'dialog'} @@ -89,222 +85,3 @@ -%script#__main__{type:'text/python3'} - :plain - import sys - import traceback - - from browser import document as doc - from browser import window, alert, console - - _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands - for supporting Python development. See www.python.org for more information.""" - - _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com - All Rights Reserved. - - Copyright (c) 2001-2013 Python Software Foundation. - All Rights Reserved. - - Copyright (c) 2000 BeOpen.com. - All Rights Reserved. - - Copyright (c) 1995-2001 Corporation for National Research Initiatives. - All Rights Reserved. - - Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. - All Rights Reserved.""" - - _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. Redistributions in binary - form must reproduce the above copyright notice, this list of conditions and - the following disclaimer in the documentation and/or other materials provided - with the distribution. - Neither the name of the nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - """ - - def credits(): - print(_credits) - credits.__repr__ = lambda:_credits - - def copyright(): - print(_copyright) - copyright.__repr__ = lambda:_copyright - - def license(): - print(_license) - license.__repr__ = lambda:_license - - def write(data): - doc['console'].value += str(data) - - - sys.stdout.write = sys.stderr.write = write - history = [] - current = 0 - _status = "main" # or "block" if typing inside a block - - # execution namespace - editor_ns = {'credits':credits, - 'copyright':copyright, - 'license':license, - '__name__':'__main__'} - - def cursorToEnd(*args): - pos = len(doc['console'].value) - doc['console'].setSelectionRange(pos, pos) - doc['console'].scrollTop = doc['console'].scrollHeight - - def get_col(area): - # returns the column num of cursor - sel = doc['console'].selectionStart - lines = doc['console'].value.split('\n') - for line in lines[:-1]: - sel -= len(line) + 1 - return sel - - - def myKeyPress(event): - global _status, current - if event.keyCode == 9: # tab key - event.preventDefault() - doc['console'].value += " " - elif event.keyCode == 13: # return - src = doc['console'].value - if _status == "main": - currentLine = src[src.rfind('>>>') + 4:] - elif _status == "3string": - currentLine = src[src.rfind('>>>') + 4:] - currentLine = currentLine.replace('\n... ', '\n') - else: - currentLine = src[src.rfind('...') + 4:] - if _status == 'main' and not currentLine.strip(): - doc['console'].value += '\n>>> ' - event.preventDefault() - return - doc['console'].value += '\n' - history.append(currentLine) - current = len(history) - if _status == "main" or _status == "3string": - try: - _ = editor_ns['_'] = eval(currentLine, editor_ns) - if _ is not None: - write(repr(_)+'\n') - doc['console'].value += '>>> ' - _status = "main" - except IndentationError: - doc['console'].value += '... ' - _status = "block" - except SyntaxError as msg: - if str(msg) == 'invalid syntax : triple string end not found' or \ - str(msg).startswith('Unbalanced bracket'): - doc['console'].value += '... ' - _status = "3string" - elif str(msg) == 'eval() argument must be an expression': - try: - exec(currentLine, editor_ns) - except: - traceback.print_exc() - doc['console'].value += '>>> ' - _status = "main" - elif str(msg) == 'decorator expects function': - doc['console'].value += '... ' - _status = "block" - else: - traceback.print_exc() - doc['console'].value += '>>> ' - _status = "main" - except: - traceback.print_exc() - doc['console'].value += '>>> ' - _status = "main" - elif currentLine == "": # end of block - block = src[src.rfind('>>>') + 4:].splitlines() - block = [block[0]] + [b[4:] for b in block[1:]] - block_src = '\n'.join(block) - # status must be set before executing code in globals() - _status = "main" - try: - _ = exec(block_src, editor_ns) - if _ is not None: - print(repr(_)) - except: - traceback.print_exc() - doc['console'].value += '>>> ' - else: - doc['console'].value += '... ' - - cursorToEnd() - event.preventDefault() - - def myKeyDown(event): - global _status, current - if event.keyCode == 37: # left arrow - sel = get_col(doc['console']) - if sel < 5: - event.preventDefault() - event.stopPropagation() - elif event.keyCode == 36: # line start - pos = doc['console'].selectionStart - col = get_col(doc['console']) - doc['console'].setSelectionRange(pos - col + 4, pos - col + 4) - event.preventDefault() - elif event.keyCode == 38: # up - if current > 0: - pos = doc['console'].selectionStart - col = get_col(doc['console']) - # remove current line - doc['console'].value = doc['console'].value[:pos - col + 4] - current -= 1 - doc['console'].value += history[current] - event.preventDefault() - elif event.keyCode == 40: # down - if current < len(history) - 1: - pos = doc['console'].selectionStart - col = get_col(doc['console']) - # remove current line - doc['console'].value = doc['console'].value[:pos - col + 4] - current += 1 - doc['console'].value += history[current] - event.preventDefault() - elif event.keyCode == 8: # backspace - src = doc['console'].value - lstart = src.rfind('\n') - if (lstart == -1 and len(src) < 5) or (len(src) - lstart < 6): - event.preventDefault() - event.stopPropagation() - - - doc['console'].bind('keypress', myKeyPress) - doc['console'].bind('keydown', myKeyDown) - doc['console'].bind('click', cursorToEnd) - v = sys.implementation.version - doc['console'].value = "Brython %s.%s.%s on %s %s\n>>> " % ( - v[0], v[1], v[2], window.navigator.appName, window.navigator.appVersion) - #doc['console'].value += 'Type "copyright", "credits" or "license" for more information.' - doc['console'].focus() - cursorToEnd() - - - - diff --git a/test/fixtures/languages.yml b/test/fixtures/languages.yml --- a/test/fixtures/languages.yml +++ b/test/fixtures/languages.yml @@ -1,34 +1,34 @@ -Language_1: +Language_c: name: c pretty_name: C ext: c common_ext: c -Language_2: +Language_cpp: name: cpp pretty_name: C++ ext: cpp common_ext: cpp,cc -Language_3: +Language_pas: name: pas pretty_name: Pascal ext: pas common_ext: pas -Language_4: +Language_ruby: name: ruby pretty_name: Ruby ext: rb common_ext: rb -Language_5: +Language_python: name: python pretty_name: Python ext: py common_ext: py -Language_6: +Language_java: name: java pretty_name: Java ext: java diff --git a/test/fixtures/problems.yml b/test/fixtures/problems.yml --- a/test/fixtures/problems.yml +++ b/test/fixtures/problems.yml @@ -1,11 +1,11 @@ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html -one: +prob_add: id: 1 name: add full_name: add_full_name available: true -two: +prob_sub: id: 2 name: subtract full_name: subtract_full_name diff --git a/test/fixtures/submissions.yml b/test/fixtures/submissions.yml --- a/test/fixtures/submissions.yml +++ b/test/fixtures/submissions.yml @@ -1,5 +1,48 @@ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html -one: +add1_by_admin: id: 1 -two: + user: admin + problem: prob_add + language: Language_c + source: + \#include + \#include + int main() { + cout << 1 << endl; + } + +sub1_by_admin: id: 2 + user: admin + problem: prob_sub + language: Language_c + source: + \#include + \#include + int main() { + cout << 2 << endl; + } + +add1_by_john: + id: 3 + user: john + problem: prob_add + language: Language_c + source: + \#include + \#include + int main() { + cout << 33 << endl; + } + +sub1_by_james: + id: 4 + user: james + problem: prob_sub + language: Language_c + source: + \#include + \#include + int main() { + cout << 44 << endl; + } diff --git a/test/system/submissions_test.rb b/test/system/submissions_test.rb new file mode 100644 --- /dev/null +++ b/test/system/submissions_test.rb @@ -0,0 +1,44 @@ +require "application_system_test_case" + +class SubmissionsTest < ApplicationSystemTestCase + # test "visiting the index" do + # visit users_url + # + # assert_selector "h1", text: "User" + # end + + test "add new submission" do + #admin can add new submission regardless of availability of the problem + login('admin','admin') + visit direct_edit_problem_submissions_path(problems(:prob_sub)) + assert_text 'Live submit' + find('.ace_text-input',visible: false).set "test code (will cause compilation error)" + click_on 'Submit' + page.accept_confirm + assert_text 'less than a minute ago' + visit logout_main_path + + #normal user can submit available problem + login('john','hello') + visit direct_edit_problem_submissions_path(problems(:prob_add)) + assert_text 'Live submit' + find('.ace_text-input',visible: false).set "test code (will cause compilation error)" + click_on 'Submit' + page.accept_confirm + assert_text 'less than a minute ago' + visit logout_main_path + + #but not unavailable problem + login('john','hello') + visit direct_edit_problem_submissions_path(problems(:prob_sub)) + assert_text 'You are not authorized' + end + + + def login(username,password) + visit root_path + fill_in "Login", with: username + fill_in "Password", with: password + click_on "Login" + end +end