Commit 21592d2d authored by Carlos Pereira Atencio's avatar Carlos Pereira Atencio Committed by carlospamg

Adding current version of ArduinoServerCompiler Python Package:

  This allows a user to run a local server, that together with the Arduino IDE allows the compilation and load of Arduino sketchs from the web interface.
parent 31c60dcf
from __future__ import unicode_literals, absolute_import
import os
try:
# 2.x name
import BaseHTTPServer
except ImportError:
# 3.x name
import http.server as BaseHTTPServer
import ArduinoServerCompiler.BlocklyRequestHandler
ADDRESS = 'localhost'
PORT = 8000
def start_server(document_root):
""" Start the server with the document root indicated by argument """
print('\nSetting HTTP Server Document Root to: \n\t' + document_root + "\n")
os.chdir(document_root)
server_address = (ADDRESS, PORT)
server = BaseHTTPServer.HTTPServer(
server_address,
ArduinoServerCompiler.BlocklyRequestHandler.BlocklyRequestHandler)
print('Launching the HTTP service...')
server.serve_forever()
print('The Server closed unexpectedly!!')
if __name__ == "__main__":
start_server(os.getcwd())
from __future__ import unicode_literals, absolute_import
import os
import cgi
try:
# 2.x name
import Tkinter
import urlparse
import tkFileDialog
import SimpleHTTPServer
except ImportError:
# 3.x name
import tkinter as Tkinter
import urllib.parse as urlparse
import tkinter.filedialog as tkFileDialog
import http.server as SimpleHTTPServer
from ArduinoServerCompiler.Py23Compatibility import Py23Compatibility
from ArduinoServerCompiler.ServerCompilerSettings import ServerCompilerSettings
from ArduinoServerCompiler.SketchCreator import SketchCreator
class BlocklyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""
Simple Python HTTP request handler to pass over the AJAX requests.
"""
def do_POST(self):
"""
Serves the POST request, using form-like data
"""
message_back = ''
parameters = None
content_type, parameters_dict = cgi.parse_header(
self.headers.getheader('content-type'))
content_length = int(self.headers.getheader('content-length'))
if content_type == 'application/x-www-form-urlencoded':
parameters = urlparse.parse_qs(
self.rfile.read(content_length), keep_blank_values=False)
#print(parameters)
#for key in parameters:
# print(str(key) + ": " + str(parameters[key]))
#parameters = cgi.FieldStorage(
# fp=self.rfile,
# headers=self.headers,
# environ={'REQUEST_METHOD':'POST',
# 'CONTENT_TYPE':self.headers['Content-Type'], })
#for item in parameters.list:
# print(item)
elif content_type == 'text/plain':
data_string = self.rfile.read(content_length)
try:
message_back = '//Python test\n\r' + data_string
except Exception as e:
print(e)
print('\nThere was an error manipulating the plain text data!!!')
else:
print('\nError, content type not recognised: ' + str(content_type))
self.send_response(404, "Upps, not found!")
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write('Error: invalid content type')
return
if message_back != '':
handle_sketch(message_back)
if parameters:
message_back = handle_settings(parameters)
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write(message_back)
#################
# Main Handlers #
#################
def handle_sketch(sketch_code):
sketch_path = create_sketch_from_string(sketch_code)
load_sketch(sketch_path)
def handle_settings(parameters):
def _get_value(parameters2):
""" Searches for a 'value' parameter in the dictionary. """
value2 = None
for key2 in parameters2:
if str(key2) == 'value':
value2 = str(parameters2[key2])
return value2
message_back = None
for key in parameters:
# Compiler
if str(key) == 'compiler':
if str(parameters[key]) == "['get']":
message_back = get_compiler_path()
elif str(parameters[key]) == "['set']":
message_back = set_compiler_path()
# Sketch
elif str(key) == 'sketch':
if str(parameters[key]) == "['get']":
message_back = get_sketch_path()
elif str(parameters[key]) == "['set']":
message_back = set_sketch_path()
# TODO: Arduino Board
# TODO: COM Port
# Load Only IDE
elif str(key) == 'ideOnly':
if str(parameters[key]) == "['get']":
message_back = get_load_ide_only()
print('ideO: ' + message_back)
elif str(parameters[key]) == "['set']":
value = _get_value(parameters)
if value == "['True']":
message_back = set_load_ide_only(True)
else:
message_back = set_load_ide_only(False)
# The Value parameter is only used in some cases
elif str(key) == 'value':
pass
# Parameter not recognised
else:
print('The "' + str(key) + '" = ' + str(parameters[key]) +
' parameter is not recognised!')
return message_back
#######################################
# Sketch loading to Arduino functions #
#######################################
def load_sketch(sketch_path=None):
"""
Launches a command line that invokes the Arduino IDE to open and/or
load an sketch, which address is indicated in the input parameter
"""
# Input sanitation
if not isinstance(sketch_path, Py23Compatibility.string_type_compare) \
or not sketch_path:
sketch_path = create_sketch_default()
# Concatenates the command string
command_line_command = ServerCompilerSettings().compiler_dir + ' '
if not ServerCompilerSettings().launch_IDE_only:
command_line_command += '--upload '
command_line_command += '--port ' + \
ServerCompilerSettings().com_port + ' '
command_line_command += '--board ' + \
ServerCompilerSettings().get_arduino_board_flag() + ' '
command_line_command += '"' + sketch_path + '"'
print('Command line command:\n\t' + command_line_command)
os.system(command_line_command)
def create_sketch_default():
return SketchCreator().create_sketch()
def create_sketch_from_string(sketch_code):
return SketchCreator().create_sketch(sketch_code)
######################################
# Dealing with Directories and files #
######################################
def browse_file():
"""
Opens a file browser and selects executable files
:return: Full path to selected file
"""
#TODO: Manually set to filder .exe files, need to make it compatible
# with other OSes
root = Tkinter.Tk()
# Make window almost invisible to focus it and ensure directory browser
# doesn't end up loading in the background behind main window.
root.withdraw()
root.overrideredirect(True)
root.geometry('0x0+0+0')
root.deiconify()
root.lift()
root.focus_force()
types = [('Executable', '.exe'), ('All Files', '*')]
file_path = tkFileDialog.askopenfilename(filetypes=types)
root.destroy()
return file_path
def browse_dir():
"""
Opens a directory browser to select a folder.
:return: Full path to the selected folder
"""
root = Tkinter.Tk()
# Make window almost invisible to focus it and ensure directory browser
# doesn't end up loading in the background behind main window.
root.withdraw()
root.overrideredirect(True)
root.geometry('0x0+0+0')
root.deiconify()
root.lift()
root.focus_force()
file_path = tkFileDialog.askdirectory(
parent=root, initialdir="/", title='Please select a directory')
root.destroy()
return file_path
#####################
# Compiler Settings #
#####################
def set_compiler_path():
"""
Open the file browser to select a file. Saves this filepath into
ServerCompilerSettings and if the filepath is different to that stored
already it triggers the new data to be saved into the settings file.
"""
old_path = get_compiler_path()
new_path = browse_file()
if new_path != '':
ServerCompilerSettings().compiler_dir = new_path
new_path = get_compiler_path()
if old_path != new_path:
ServerCompilerSettings().save_settings()
return new_path
def get_compiler_path():
return ServerCompilerSettings().compiler_dir
###################
# Sketch settings #
###################
def set_sketch_path():
"""
Open the directory browser to select a file. Saves this directory into
ServerCompilerSettings and if the directory is different to that stored
already it triggers the new data to be saved into the settings file.
"""
old_directory = get_sketch_path()
new_directory = browse_dir()
if new_directory != '':
ServerCompilerSettings().sketch_dir = new_directory
new_directory = get_sketch_path()
if old_directory != new_directory:
ServerCompilerSettings().save_settings()
return new_directory
def get_sketch_path():
return ServerCompilerSettings().sketch_dir
############################
# Launch IDE only settings #
############################
def set_load_ide_only(new_value):
ServerCompilerSettings().launch_IDE_only = new_value
return get_load_ide_only()
def get_load_ide_only():
return str(ServerCompilerSettings().launch_IDE_only)
########
# Main #
########
def main():
print("This is the BlocklyRequestHandler main.")
if __name__ == "__main__":
main()
"""
This module contains some utilities to maintain compatibility between python 2.5+ and 3
"""
from __future__ import unicode_literals, absolute_import
import sys
import types
# Define different types for comparison
if sys.version_info[0] == 3:
string_type_compare = str
integer_type_compare = int
class_type_compare = type
else:
string_type_compare = basestring
integer_type_compare = (int, long)
class_type_compare = (type, types.ClassType)
from __future__ import unicode_literals, absolute_import
import os
import re
import types
import sys
try:
# 2.x name
import ConfigParser
except ImportError:
# 3.x name
import configparser as ConfigParser
class ServerCompilerSettings(object):
"""
Retrieves and saves the settings for the server side compilation.
No compiler is part of the Python code, instead settings that
point to the local Arduino IDE and sketch are stored here.
"""
# Designed to be class static variables
__singleton_instance__ = None
__settings_filename__ = 'ServerCompilerSettings.ini'
__settings_path__ = None
# This is a static dictionary to define Arduino board types
__arduino_types__ = {'Uno': 'arduino:avr:uno',
'Leonardo': 'arduino:avr:leonardo',
'Mega': 'arduino:avr:mega',
'Duemilanove_328p': 'arduino:avr:diecimila',
'Duemilanove_168p': 'arduino:avr:diecimila:cpu=atmega168'}
#
# Singleton creator and destructor
#
def __new__(cls, *args, **kwargs):
""" Creating or returning the singleton instance """
if not cls.__singleton_instance__:
# Create the singleton instance
cls.__singleton_instance__ =\
super(ServerCompilerSettings, cls).__new__(cls, *args, **kwargs)
# Initialise the instance, defaults if file not found
cls.__singleton_instance__.__initialise()
return cls.__singleton_instance__
def __initialise(self):
# Create variables to be used with accessors
self.__launch_IDE_only__ = False
self.__compiler_dir__ = None
self.__sketch_dir__ = None
self.__sketch_name__ = None
self.__arduino_board_key__ = None
self.__arduino_board_value__ = None
self.__com_port__ = None
# Load settings from file
self.read_settings()
def _drop(self):
""" Drop the instance """
self.__singleton_instance__ = None
#
# Compiler Directory accessors
#
def get_compiler_dir(self):
return self.__compiler_dir__
def set_compiler_dir(self, new_compiler_dir):
""" The compiler dir must be full path to an .exe file """
# FIXME: this is a windows only check (.exe), needs to be
# updated to be compatible with linux and MacOS
if os.path.exists(new_compiler_dir) and\
new_compiler_dir.endswith('.exe'):
self.__compiler_dir__ = new_compiler_dir
else:
print('\nThe provided compiler path is not valid !!!')
print('\t' + new_compiler_dir)
if self.__compiler_dir__:
print('Previous compiler path maintained:')
else:
print('Default compiler path set:')
self.set_compiler_dir_default()
print('\t' + self.__compiler_dir__)
compiler_dir = property(get_compiler_dir, set_compiler_dir)
def set_compiler_dir_default(self):
self.__compiler_dir__ = 'C:\\IDEs\\arduino-1.5.6-r2\\arduino.exe'
#
# Arduino Board and board lists accessors
#
def get_arduino_board(self):
return self.__arduino_board_key__
def set_arduino_board(self, new_board):
if new_board in self.__arduino_types__:
self.__arduino_board_value__ = self.__arduino_types__[new_board]
self.__arduino_board_key__ = new_board
else:
print('\nProvided Arduino Board does not exist: !!!')
print('\t' + new_board)
if self.__arduino_board_key__ and self.__arduino_board_value__:
print('Previous Arduino board type maintained:')
else:
print('Default Arduino board type set:')
self.set_arduino_board_default()
print('\t' + self.__arduino_board_key__)
arduino_board = property(get_arduino_board, set_arduino_board)
def set_arduino_board_default(self):
self.__arduino_board_key__ = 'Uno'
self.__arduino_board_value__ = \
self.__arduino_types__[self.__arduino_board_key__]
def get_arduino_board_flag(self):
return self.__arduino_board_value__
def get_arduino_board_types(self):
board_list = []
for key in self.__arduino_types__:
board_list.append(key)
return board_list
#
# Sketch name accessors
#
def get_sketch_name(self):
return self.__sketch_name__
def set_sketch_name(self, new_sketch_name):
""" Only accept letters, numbers, underscores and dashes """
if re.match("^[\w\d_-]*$", new_sketch_name):
self.__sketch_name__ = new_sketch_name
else:
print('\nProvided Sketch name is not valid: !!!')
print('\t' + new_sketch_name)
if self.__sketch_name__:
print('Previous Sketch name maintained:')
else:
print('Default Sketch name set:')
self.set_sketch_name_default()
print('\t' + self.__sketch_name__)
sketch_name = property(get_sketch_name, set_sketch_name)
def set_sketch_name_default(self):
self.__sketch_name__ = 'ArdublocklySketch'
#
# Sketch Directory accessors
#
def get_sketch_dir(self):
return self.__sketch_dir__
def set_sketch_dir(self, new_sketch_dir):
""" The sketch directory must be a folder """
if os.path.isdir(new_sketch_dir):
self.__sketch_dir__ = new_sketch_dir
else:
print('\nThe provided sketch directory is not valid !!!')
print('\t' + new_sketch_dir)
if self.__sketch_dir__:
print('Previous Sketch directory maintained:')
else:
print('Default Sketch directory set:')
self.set_sketch_dir_default()
print('\t' + self.__sketch_dir__)
sketch_dir = property(get_sketch_dir, set_sketch_dir)
def set_sketch_dir_default(self):
self.__sketch_dir__ = os.getcwd()
#
# Launch the IDE only accessors
#
def get_launch_ide_only(self):
return self.__launch_IDE_only__
def set_launch_ide_only(self, new_launch_ide_only):
if isinstance(new_launch_ide_only, types.BooleanType):
self.__launch_IDE_only__ = new_launch_ide_only
else:
print('\nThe provided "Launch IDE only" boolean is not valid !!!')
print('\t' + new_launch_ide_only)
if self.__launch_IDE_only__:
print('Previous "Launch IDE only" boolean maintained:')
else:
print('Default "Launch IDE only" boolean set:')
self.set_launch_ide_only_default()
print('\t' + self.__launch_IDE_only__)
launch_IDE_only = property(get_launch_ide_only, set_launch_ide_only)
def set_launch_ide_only_default(self):
self.__launch_IDE_only__ = False
#
# Communications Port accessors
#
# TODO: COM port accessors properly
def get_com_port(self):
return self.__com_port__
def set_com_port(self, new_com_port):
self.__com_port__ = new_com_port
com_port = property(get_com_port, set_com_port)
def set_com_port_default(self):
self.__com_port__ = 'COM1'
#
# Sets all the settings to default values
#
def set_default_settings(self):
self.set_launch_ide_only_default()
self.set_compiler_dir_default()
self.set_sketch_dir_default()
self.set_sketch_name_default()
self.set_com_port_default()
self.set_arduino_board_default()
#
# Settings file
#
def save_settings(self):
""" Saves the settings in a configuration file """
settings_parser = ConfigParser.ConfigParser()
# IDE Section
settings_parser.add_section('Arduino_IDE')
settings_parser.set(
'Arduino_IDE', 'arduino_exec_path', self.compiler_dir)
settings_parser.set(
'Arduino_IDE', 'arduino_board', self.arduino_board)
settings_parser.set(
'Arduino_IDE', 'arduino_com_port', self.com_port)
# Sketch section
settings_parser.add_section('Arduino_Sketch')
settings_parser.set(
'Arduino_Sketch', 'sketch_name', self.sketch_name)
settings_parser.set(
'Arduino_Sketch', 'sketch_directory', self.sketch_dir)
# Set the path and create/overwrite the file
try:
settings_file = open(self.get_settings_file_path(), 'w')
settings_parser.write(settings_file)
settings_file.close()
print('\nSettings file saved to:')
except Exception as e:
print(e)
print('\nUnable to write the settings file to:')
print('\t' + self.get_settings_file_path())
def read_settings(self):
"""
Attempts to read the settings from a file and saves them to the
member variables. If it cannot read the file it sets the variables
to the default value.
"""
settings_dict = self.read_settings_file()
if settings_dict:
self.compiler_dir = settings_dict['arduino_exec_path']
self.arduino_board = settings_dict['arduino_board']
self.com_port = settings_dict['arduino_com_port']
self.sketch_name = settings_dict['sketch_name']
self.sketch_dir = settings_dict['sketch_directory']
else:
print('\nSettings will be set to the default values.')
self.set_default_settings()
self.save_settings()
# Printing the settings to be able to easily spot issues at load
print('\nFinal settings loaded:')
print('\tCompiler directory: ' + self.__compiler_dir__)
print('\tArduino Board Key: ' + self.__arduino_board_key__)
print('\tArduino Board Value: ' + self.__arduino_board_value__)
print('\tCOM Port: ' + self.__com_port__)
print('\tSketch Name: ' + self.__sketch_name__)
print('\tSketch Directory: ' + self.__sketch_dir__)
print('\tLaunch IDE only: ' + str(self.__launch_IDE_only__))
def read_settings_file(self):
"""
Creates a dictionary from the settings stored in a file.
:return: A dictionary with all the options and values from the settings
file (sections are ignored during parsing).
"""
settings_dict = {}
settings_parser = ConfigParser.ConfigParser()
try:
settings_parser.read(self.get_settings_file_path())
settings_dict['arduino_exec_path'] =\
settings_parser.get('Arduino_IDE', 'arduino_exec_path')
settings_dict['arduino_board'] =\
settings_parser.get('Arduino_IDE', 'arduino_board')
settings_dict['arduino_com_port'] =\
settings_parser.get('Arduino_IDE', 'arduino_com_port')
settings_dict['sketch_name'] =\
settings_parser.get('Arduino_Sketch', 'sketch_name')
settings_dict['sketch_directory'] =\
settings_parser.get('Arduino_Sketch', 'sketch_directory')
print('\nSettings loaded from:')
except Exception as e:
print('\nSettings file corrupted or not found in:')
settings_dict = None
print('\t' + self.get_settings_file_path())
return settings_dict
def delete_settings_file(self):
if os.path.exists(self.get_settings_file_path()):
os.remove(self.get_settings_file_path())
def get_settings_file_path(self):
"""
Returns the settings file path or creates the path if not invoked before.
The file is saved in the same directory as this python source code file.
:return: path to the settings file
"""
if not self.__settings_path__:
self.__settings_path__ = os.path.join(
os.path.dirname(__file__), self.__settings_filename__)
return self.__settings_path__
def get_board_value_from_key(self, string_key):
"""
As the board types are stored in a dictionary, the key and value for
the selected board are stored independently in 2 strings. This method
gets the dictionary value from a given key.
:param string_key: String representing the board_types dictionary key
:return: A string representation of board_types dictionary value from
the key.
"""
string_value = None
for key in self.__arduino_types__:
if string_key is key:
string_value = self.__arduino_types__[key]
return string_value
def get_board_key_from_value(self, string_value):
"""
As the board types are stored in a dictionary, the key and value for
the selected board are stored independently in 2 strings. This method
gets the dictionary key from a given value.
:param string_value: String representing the board_types dictionary
value to be found.
:return: A string representation of board_types dictionary key for
the given value.
"""
string_key = None
for key in self.__arduino_types__:
if string_value is self.__arduino_types__[key]:
string_key = key
return string_key
def main():
""" This should never be executed """
print("This is the ServerCompilerSettings main")
if __name__ == '__main__':
main()
from __future__ import unicode_literals, absolute_import
import os
from ArduinoServerCompiler.Py23Compatibility import Py23Compatibility
from ArduinoServerCompiler.ServerCompilerSettings import ServerCompilerSettings
class SketchCreator(object):
"""
Creates an Arduino Sketch
"""
#This is probably not the best way to create this string, will revisit
_sketch_default_code = """int led = 13;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH);
delay(1000);
digitalWrite(led, LOW);
delay(1000);
}"""
#
# Constructor
#
def __init__(self):
pass
#
# Creating files
#
def create_sketch(self, sketch_code=None):
"""
Creates the Ardunino sketch with either the default blinky
code or the code defined in the input parameter
:param sketch_code: Unicode string with the code for the sketch
:return: Unicode string with full path to the sketch file
Return None indicates an error has occurred
"""
sketch_path = self.build_sketch_path()
if isinstance(sketch_code, Py23Compatibility.string_type_compare)\
and sketch_code:
code_to_write = sketch_code
else:
code_to_write = self._sketch_default_code
try:
arduino_sketch = open(sketch_path, 'w')
arduino_sketch.write(code_to_write)
arduino_sketch.close()
except Exception as e:
sketch_path = None
print(e)
print('Arduino sketch could not be created!!!')
return sketch_path
#
# File and directories settings
#
def build_sketch_path(self):
"""
If a valid directory is saved in the settings, it creates the Arduino
folder (if it does not exists already) and returns a string pointing
to the sketch path
:return: unicode string with full path to the sketch file
Return None indicates an error has occurred
"""
sketch_name = ServerCompilerSettings().sketch_name
sketch_directory = ServerCompilerSettings().sketch_dir
sketch_path = None
if os.path.isdir(sketch_directory):
sketch_path = os.path.join(sketch_directory, sketch_name)
if not os.path.exists(sketch_path):
os.makedirs(sketch_path)
sketch_path = os.path.join(sketch_path, sketch_name + '.ino')
else:
print('The sketch directory in the settings does not exists!')
return sketch_path
def main():
# This should never be executed
print("This is the SketchCreator main")
if __name__ == "__main__":
main()
from __future__ import unicode_literals, absolute_import
import os
import unittest
import mock
import ParentDirToSysPath
from BlocklyServerCompiler import BlocklyRequestHandler
class BlocklyRequestHandlerTestCase(unittest.TestCase):
"""
Tests for BlocklyRequestHandler module
"""
#
# Command line tests
#
@mock.patch('BlocklyServerCompiler.BlocklyRequestHandler.os')
@mock.patch('BlocklyServerCompiler.BlocklyRequestHandler.create_sketch_default')
@mock.patch.object(BlocklyRequestHandler.ServerCompilerSettings, 'get_compiler_dir', autospec=True)
def test_command_line_launch(self, mock_settings, mock_sketch, mock_os):
"""
Tests that a compiler path and arduino sketch path can be set
and that a command line can be launched to open the sketch in the
Arduino IDE
"""
# Set the compiler settings
test_sketch_path = os.path.join(os.getcwd(), 'sketch.ino')
mock_sketch.return_value = test_sketch_path
test_compiler_dir = os.path.join(os.getcwd(), 'arduino.exe')
mock_settings = BlocklyRequestHandler.ServerCompilerSettings()
mock_settings.__compiler_dir__ = test_compiler_dir
BlocklyRequestHandler.ServerCompilerSettings().launch_IDE_only = True
# Build expected string and run test
expected_command = test_compiler_dir + ' "' + test_sketch_path + '"'
BlocklyRequestHandler.load_sketch()
mock_os.system.assert_called_with(expected_command)
#
# Tests for checking browsing for paths and files
#
@mock.patch('BlocklyServerCompiler.BlocklyRequestHandler.tkFileDialog')
def test_browse_file(self, mock_file_select):
test_file = 'test_file'
mock_file_select.askopenfilename.return_value = test_file
new_file = BlocklyRequestHandler.browse_file()
self.assertEqual(new_file, test_file)
def test_browse_file_cancel(self):
canceled_file = ''
print('A file browser window will open, to successfully run this test '
'press cancel or close the window!!!\n')
#raw_input('Press "Enter" to continue...')
function_file = BlocklyRequestHandler.browse_file()
self.assertEqual(canceled_file, function_file)
@mock.patch('BlocklyServerCompiler.BlocklyRequestHandler.tkFileDialog')
def test_browse_path(self, mock_path_select):
test_path = 'test_path'
mock_path_select.askopenfilename.return_value = test_path
new_path = BlocklyRequestHandler.browse_file()
self.assertEqual(new_path, test_path)
def test_browse_path_cancel(self):
canceled_path = ''
print('A path browser window will open, to successfully run this test '
'press cancel or close the window!!!\n')
#raw_input('Press "Enter" to continue...')
function_path = BlocklyRequestHandler.browse_dir()
self.assertEqual(canceled_path, function_path)
if __name__ == '__main__':
unittest.main()
"""
This is a very simple module to import the parent directory to the system path
so that all the test files are able to correctly import the required module
under test
"""
from __future__ import unicode_literals, absolute_import
import os
import sys
# Import the parent directory into the system path
#sys.path.append(os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir))
sys.path.append(os.path.dirname(os.path.dirname(os.getcwd())))
\ No newline at end of file
[Arduino_IDE]
arduino_exec_path = C:\IDEs\arduino-1.5.6-r2\arduino.exe
arduino_board = Uno
arduino_com_port = COM1
[Arduino_Sketch]
sketch_name = BlocklyDuinoSketch
sketch_directory = C:\Users\nggmcao\Desktop\volunteering\BlocklyDuino-BtW\BlocklyServerCompiler\tests
from __future__ import unicode_literals, absolute_import
import os
import unittest
import mock
import ParentDirToSysPath
from BlocklyServerCompiler.ServerCompilerSettings import ServerCompilerSettings
class ServerCompilerSettingsTestCase(unittest.TestCase):
"""
Tests for ServerCompilerSettings
"""
#
# Testing the class singlentoness
#
def test_singleton(self):
# Testing if singleton is working
instance_1 = ServerCompilerSettings()
instance_2 = ServerCompilerSettings()
self.assertEqual(id(instance_1), id(instance_2))
def test_destructor(self):
ServerCompilerSettings()
instance_1 = ServerCompilerSettings()
instance_1._drop()
self.assertEqual(instance_1.__singleton_instance__, None)
#
# Testing the compiler_dir getter and setter
#
def test_read_compiler_dir(self):
self.assertEqual(ServerCompilerSettings().compiler_dir, ServerCompilerSettings().__compiler_dir__)
@mock.patch('BlocklyServerCompiler.ServerCompilerSettings.os.path.exists')
def test_write_compiler_dir_invalid(self, mock_os_path_exists):
"""
Tests path doesn't get save if:
A file that does not exists
Just a folder
A non executable file
"""
# TODO: a file that 'exists but does not execute' is not done
# Random file
mock_os_path_exists.return_value = False
original_dir = ServerCompilerSettings().compiler_dir
new_dir = os.path.join(os.getcwd(), 'random.exe')
ServerCompilerSettings().compiler_dir = new_dir
self.assertNotEqual(new_dir, ServerCompilerSettings().compiler_dir)
self.assertEqual(original_dir, ServerCompilerSettings().compiler_dir)
# Just a folder
mock_os_path_exists.return_value = True
new_dir = os.getcwd()
ServerCompilerSettings().compiler_dir = new_dir
self.assertNotEqual(new_dir, ServerCompilerSettings().compiler_dir)
self.assertEqual(original_dir, ServerCompilerSettings().compiler_dir)
# Non .exe file
mock_os_path_exists.return_value = True
new_dir = os.path.join(os.getcwd(), 'arduino.txt')
ServerCompilerSettings().compiler_dir = new_dir
self.assertNotEqual(new_dir, ServerCompilerSettings().compiler_dir)
self.assertEqual(original_dir, ServerCompilerSettings().compiler_dir)
@mock.patch('BlocklyServerCompiler.ServerCompilerSettings.os.path.exists')
def test_write_compiler_dir_valid(self, mock_os_path_exists):
mock_os_path_exists.return_value = True
new_dir = os.path.join(os.getcwd(), 'arduino.exe')
ServerCompilerSettings().compiler_dir = new_dir
self.assertEqual(new_dir, ServerCompilerSettings().compiler_dir)
#
# Testing the settings file
#
def test_settings_file_creation(self):
""" Need to find a way to test this one """
ServerCompilerSettings().save_settings()
self.assertEqual(0,0)
def test_settings_file_read(self):
ServerCompilerSettings()
ServerCompilerSettings().set_default_settings()
ServerCompilerSettings().read_settings_file()
ServerCompilerSettings().save_settings()
if __name__ == '__main__':
unittest.main()
from __future__ import unicode_literals, absolute_import
import os
import unittest
import ParentDirToSysPath
from BlocklyServerCompiler.SketchCreator import SketchCreator
from BlocklyServerCompiler.ServerCompilerSettings import ServerCompilerSettings
class SketchCreatorTestCase(unittest.TestCase):
"""
Tests for SketchCreator class
"""
#
# File creation
#
def test_create_directory(self):
""" Tests to see if an Arduino Sketch is created in a new location """
test_sketch_name = 'TestTemp_Sketch'
ServerCompilerSettings().sketch_dir = os.getcwd()
ServerCompilerSettings().sketch_name = test_sketch_name
test_path = os.path.join(os.getcwd(),
test_sketch_name,
test_sketch_name + '.ino')
# It should be save to create and delete in test folder
if os.path.exists(test_path):
os.remove(test_path)
print('\ntest_createDirectory() message:')
print("Check location: " + test_path)
instance_1 = SketchCreator()
created_sketch_path = instance_1.create_sketch()
self.assertEqual(test_path, created_sketch_path)
#
# File creation with code
#
def test_create_sketch_with_code(self):
sketch_code_write = 'This is a test'
instance_1 = SketchCreator()
sketch_location = instance_1.create_sketch(sketch_code_write)
print('\ntest_create_sketch_with_code() message:')
print("Check location: " + sketch_location)
arduino_sketch = open(sketch_location, 'r')
sketch_code_read = arduino_sketch.read()
arduino_sketch.close()
self.assertEqual(sketch_code_write, sketch_code_read)
if __name__ == '__main__':
unittest.main()
from __future__ import unicode_literals, absolute_import
import unittest
import ParentDirToSysPath
from BlocklyServerCompiler.XXXX import XXXX
class XXXXTestCase(unittest.TestCase):
"""
Tests for XXXX
"""
#
# Test category
#
def test_XXX(self):
""" Tests description if not obvious """
self.assertEqual(a, b)
self.assertNotEqual(a, b)
if __name__ == '__main__':
unittest.main()
#!/usr/bin/env python2
# ##############################################################################
# The comment above works if the Python Launcher for Windows path included
# in Python>3.3 does not conflict with the py.exe file added to "C:\Windows"
# Currently this application should work in Python >2.6 and 3.x, although
# python 2 is prefered, as it is the main development platform.
###############################################################################
from __future__ import unicode_literals, absolute_import
import os
import platform
import threading
import webbrowser
import ArduinoServerCompiler.ServerCompilerSettings
import ArduinoServerCompiler.BlocklyHTTPServer
def open_browser(filetoload):
""" Start a browser after waiting for half a second. """
def _open_browser():
webbrowser.open('http://%s:%s/%s' %
(ArduinoServerCompiler.BlocklyHTTPServer.ADDRESS,
ArduinoServerCompiler.BlocklyHTTPServer.PORT,
filetoload))
thread = threading.Timer(0.5, _open_browser)
thread.start()
def main():
"""
Initialises the Settings singleton and starts the HTTP Server
"""
print('Running Python version ' + platform.python_version())
print("\n======= Loading Settings =======")
ArduinoServerCompiler.ServerCompilerSettings.ServerCompilerSettings()
current_dir = os.getcwd()
app_index = os.path.basename(os.path.normpath(current_dir))
app_index = os.path.join(app_index, 'apps', 'arduino')
open_browser(app_index)
print("\n======= Starting Server =======")
#parent directory as working directory due to closure requirements
parent_dir = os.path.dirname(os.getcwd())
ArduinoServerCompiler.BlocklyHTTPServer.start_server(parent_dir)
if __name__ == "__main__":
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment