From 0868e0642f694bf5c08951f67f5a4b7eadde041a Mon Sep 17 00:00:00 2001 From: Jacek Kowalski <Jacek@jacekk.info> Date: Thu, 05 Sep 2013 21:22:22 +0000 Subject: [PATCH] Zmiana numeru wersji na 2.6, testy jednostkowe niektórych klas (PHPUnit), dodanych wiele komentarzy dotyczących metod oraz atrybutów (Doxygen), aktualizacja instrukcji instalacji i aktualizacji. --- INSTALL | 7 class/legacy/jsarray.php | 17 tests/Core/BotMsgTest.php | 99 ++++++ class/legacy/calendar.php | 6 class/legacy/funcs.php | 13 class/BotMessage.php | 31 + class/BotModule.php | 40 ++ class/legacy/main.php | 10 class/BotSession.php | 73 +++ Doxyfile | 285 +++++++++++++++++++ tests/Core/BotSessionTest.php | 136 +++++++++ class/BotImageGG.php | 2 class/legacy/module.php | 15 tests/Core/Legacy/JSArrayTest.php | 29 + class/BotMsg.php | 46 ++ phpunit.xml | 10 class/BotImage.php | 17 + class/BotUser.php | 21 + tests/Core/BotMessageTest.php | 13 .travis.yml | 8 tests/autoload.php | 2 UPGRADE | 11 class/std.php | 6 23 files changed, 839 insertions(+), 58 deletions(-) diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2e72fdc --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: php +php: + - 5.5 + - 5.4 + - 5.3 + - 5.2 + +script: phpunit --coverage-text diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..6eb6f66 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,285 @@ +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Bot Gadu-Gadu" +PROJECT_NUMBER = +OUTPUT_DIRECTORY = docs +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = Polish +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.php +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */docs/* */data/* */tests/* */modules/* +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_TIMESTAMP = YES +HTML_ALIGN_MEMBERS = YES +HTML_DYNAMIC_SECTIONS = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +USE_INLINE_TREES = NO +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_FONTNAME = FreeSans +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/INSTALL b/INSTALL index 9529f18..64411ae 100644 --- a/INSTALL +++ b/INSTALL @@ -8,8 +8,6 @@ http://dev.gg.pl/api/pages/botapi.html#rejestracja * ustaw serwer WWW tak, by plik BotGG.php był wykonywany po wejściu na ustalony przy rejestracji adres -* ustaw serwer WWW tak, by plik BotIMI.php był wykonywany po wejściu na - ustalony w IMified.com adres * zmień /sciezka/do/bota w pliku data/update.sh na rzeczywistą, bezwzględną ścieżkę do katalogu skryptu * wykonuj za pomocą crona polecenie `/sciezka/do/bota/data/update.sh` ok. @@ -34,12 +32,13 @@ ------- Jeśli dodajesz/usuwasz moduły lub komendy KONIECZNIE usuń wszystkie pliki -z katalogu ./cache - w przeciwnym wypadku polecenia te mogą powodować błędy -w działaniu bota! +z katalogu ./cache - w przeciwnym wypadku może to powodować błędy +w działaniu całego bota! ------------ INFORMACJA ------------ + W razie problemów zacznij od zmiany error_reporting(E_COMPILE_ERROR|E_PARSE); na diff --git a/UPGRADE b/UPGRADE index 1c01ce2..28d3823 100644 --- a/UPGRADE +++ b/UPGRADE @@ -1,3 +1,14 @@ +Wersję można sprawdzić w pliku ./class/legacy/main.php + +=========================== + AKTUALIZACJA Z WERSJI 2.5 +=========================== + +* nadpisz wszystkie pliki w katalogu ./class (oraz podkatalogach), + za wyjątkiem ./class/config.php +* zastąp plik ./data/lotto/pobierz.php +* zastąp plik ./data/tv/wp_parse.php + =========================== AKTUALIZACJA Z WERSJI 2.4 =========================== diff --git a/class/BotImage.php b/class/BotImage.php index c02bcf0..e482302 100644 --- a/class/BotImage.php +++ b/class/BotImage.php @@ -1,7 +1,24 @@ <?php +/** + * Interfejs do obsługi obrazków przychodzących + */ abstract class BotImage { + /** + * Zmienna przechowująca zasób biblioteki GD2 z obrazkiem + * @var resource $data + */ protected $data = NULL; + + /** + * Funkcja zwracająca zasób GD2 z obrazkiem + * @return resource Zasób GD2 + */ abstract function getImage(); + + /** + * Funkcja zwracająca dane obrazka w formie ciągu bajtów. + * @return string Obrazek + */ abstract function getImageData(); } ?> \ No newline at end of file diff --git a/class/BotImageGG.php b/class/BotImageGG.php index 846388e..ad0ea8b 100644 --- a/class/BotImageGG.php +++ b/class/BotImageGG.php @@ -16,7 +16,7 @@ function getImageData() { if($this->data === NULL) { - $push = new BotGGAPI(); + $push = new BotAPIGG(); $this->data = $push->getImage($this->hash); } diff --git a/class/BotMessage.php b/class/BotMessage.php index a958902..30416f8 100644 --- a/class/BotMessage.php +++ b/class/BotMessage.php @@ -2,58 +2,71 @@ class BotMessage { /** * Informacje o kliencie - * @var BotUser + * @var BotUser $user */ protected $user; + /** * Informacje o kliencie zgodne z poprzednią wersją Bota (dot. API IMified). * Najczęściej równe {@link BotMessage::$user} - * @var BotUser + * @var BotUser $userAlt */ protected $userAlt; /** * Sesja przypisana do użytkownika i modułu - * @var BotSession + * @var BotSession $session */ protected $session; /** * Tekst otrzymany od API - bez zmian - * @var string + * @var string $rawText */ protected $rawText; /** * Czysty tekst, tylko znaki ASCII, małe litery, podwójne spacje zamienione na pojedyncze - * @var string + * @var string $text */ protected $text; /** - * Tablica obrazków (zobacz klasę BotImage) przesłanych do bota przez użytkownika. - * @var array + * Tablica obrazków (zobacz {@link BotImage}) przesłanych do bota przez użytkownika. + * @var array $images */ protected $images = array(); /** * Komenda, tylko znaki ASCII, małe litery - * @var string + * @var string $command */ private $command; /** * Argumenty polecenia - oryginalne - * @var string + * @var string $args */ private $args; + /** + * Umożliwia dostęp tylko do odczytu do prywanych zmiennych + * @param string $name Nazwa zmiennej + * @return mixed Wartość zmiennej prywatnej + */ function __get($name) { return $this->$name; } + /** + * Na podstawie nieprzetworzonej wiadomości ({@link BotMessage::$rawText}) + * metoda ustawia wszystkie pola klasy. + * @param string $value Nieprzetworzona wiadomość + */ function setText($value) { $this->rawText = $value; + + $value = trim($value); $this->text = funcs::utfToAscii($value); $this->command = funcs::utfToAscii(trim(strtok($value, " \t\r\n"))); $this->args = trim(strtok('')); diff --git a/class/BotModule.php b/class/BotModule.php index 87df80e..482edd5 100644 --- a/class/BotModule.php +++ b/class/BotModule.php @@ -1,11 +1,47 @@ <?php class BotModuleException extends Exception {} -interface BotModule { -} +interface BotModule {} +/** + * Interfejs klasy inicjującej moduł bota + */ interface BotModuleInit { + /** + * Funkcja zwracająca listę obsługiwanych komend. + * Przykład: + * <pre>array( + * 'komenda' => array( + * array( + * 'file' => 'komenda.php', + * 'class' => 'bot_NAZWAMODULU_module', + * 'method' => 'komenda1', + * 'params' => 'parametr_do_funkcji', + * ), + * array( + * 'file' => 'komenda.php', + * 'class' => 'bot_NAZWAMODULU_module', + * 'method' => 'komenda2', + * ), + * ), + * '*' => array( + * array( + * 'file' => 'test.php', + * 'class' => 'NAZWAMODULU_test', + * 'method' => 'komenda_test', + * ), + * ), + * )</pre> + * @return array Lista obsługiwanych komend + */ function register(); + + /** + * Zwraca pomoc dla polecenia lub skróconą listę poleceń + * obsługiwanych przez dany moduł. + * @param string|NULL $params Nazwa komendy + * @return BotMsg Pomoc dla komendy + */ function help($params = NULL); } ?> \ No newline at end of file diff --git a/class/BotMsg.php b/class/BotMsg.php index 54c6afa..bf58ce9 100644 --- a/class/BotMsg.php +++ b/class/BotMsg.php @@ -1,11 +1,33 @@ <?php class BotMsgException extends Exception {} + +/** + * Interfejs dla klas przetwarzających wiadomości wychodzące + * do formatu właściwego dla danej sieci. + */ interface BotMsgInterface { + /** + * Konstruktor + * @param BotMsg $msg Wiadomość do przetworzenia + */ function __construct(BotMsg $msg); + /** + * Zwraca przetworzoną wiadomość + * @return string Wiadomość po przetworzeniu + */ function __toString(); + + /** + * Podaje na wyjście (np. za pomocą echo) wiadomość w formacie + * odpowiednim dla danego API, uwzględniając nagłówki HTTP + * i inne konieczne elementy. + */ function sendPullResponse(); } +/** + * Klasa reprezentująca wiadomość wychodzącą. + */ class BotMsg { private $beautiful = TRUE; private $parser = NULL; @@ -14,14 +36,28 @@ private $raw = ''; /** - * Włącza lub wyłącza "upiększanie" konwertowanej do czystego tekstu wiadomości, np.: - * <b>abc</b> zamieniane jest na *abc* - * <h1>efg</h1> przechodzi w = efg = + * Włącza lub wyłącza "upiększanie" konwertowanej + * do czystego tekstu ({@link BotMsg::getText()}) wiadomości, np.: + * + * <b>abc</b> zamieniane jest na \*abc\* + * + * <h1>efg<h1> przechodzi w = efg = + * * Domyślnie włączone * @param bool $set Ustawienie "upiększania" */ + function setBeautiful($set = FALSE) { + if($this->beautiful != $set) { + $this->text = $this->html = $this->parser = NULL; + $this->beautiful = (bool)$set; + } + } + + /** + * @deprecated Zastąpiono funkcją {@link BotMsg::setBeautiful()} + */ function beautifulText($set = FALSE) { - $this->beautiful = (bool)$set; + $this->setBeautiful($set); } /** @@ -204,7 +240,7 @@ } } - return $return; + return trim($return); } private function parseHTMLDOM($dom) { diff --git a/class/BotSession.php b/class/BotSession.php index 36cd174..61511db 100644 --- a/class/BotSession.php +++ b/class/BotSession.php @@ -1,18 +1,29 @@ <?php /** - * Klasa przechowująca dane użytkownika. Całość przypomina mechanizm sesji w PHP. + * Klasa przechowująca dane przekazane przez użytkownika, + * w szczególności jego ustawienia. */ class BotSession { private $PDO; /** * Nazwa modułu, którego zmienne klasa przetwarza - * @var string max. 40 znaków + * @var string $class max. 40 znaków */ protected $class = ''; protected $class_empty = TRUE; + /** + * Pseudo-URL użytkownika. + * @see BotUser + * @var string $user URL użytkownika + */ private $user; + /** + * Klasa z identyfikatorem użytkownika + * @var BotUser $user_struct + */ + private $user_struct; /** * Inicjuje klasę w zależności od użytkownika @@ -55,10 +66,10 @@ $version = 1; } - if($version < 3) { + if($version < 4) { $this->PDO->query('DELETE FROM data WHERE class IS NULL AND name=\'user_struct\''); - $this->PDO->query('INSERT OR REPLACE INTO data (class, name, value) VALUES (\'\', \'_version\', 3)'); - $version = 3; + $this->PDO->query('INSERT OR REPLACE INTO data (class, name, value) VALUES (\'\', \'_version\', 4)'); + $version = 4; } return; @@ -71,7 +82,7 @@ $this->PDO->query( 'CREATE TABLE data ( - class VARCHAR(50), + class VARCHAR(50) NOT NULL DEFAULT \'\', name VARCHAR(40) NOT NULL, value TEXT NOT NULL, PRIMARY KEY ( @@ -81,6 +92,8 @@ )' ); + $this->PDO->query('INSERT INTO data (class, name, value) VALUES (\'\', \'_version\', 4)'); + $files = glob(BOT_TOPDIR.'/db/*/'.$this->user_struct['user'].'.ggdb'); if(!$files) { return; @@ -89,12 +102,10 @@ $this->PDO->beginTransaction(); $st = $this->PDO->prepare('INSERT OR REPLACE INTO data (class, name, value) VALUES (?, ?, ?)'); - $st->execute(array('', '_version', 2)); - foreach($files as $file) { $data = unserialize(file_get_contents($file)); foreach($data as $name => $value) { - $st->execute(array($this->class, $name, $value)); + $st->execute(array($this->class, $name, serialize($value))); } } @@ -112,6 +123,19 @@ } } + /** + * Ustawia nazwę modułu/klasy, której zmienne będą przetwarzane + * @param string $class Nazwa modułu + */ + function setClass($class) { + $this->class = $class; + } + + /** + * Pobiera zmienną modułu o podanej nazwie (getter). + * @param string $name Nazwa zmiennej + * @return mixed Wartość zmiennej lub NULL + */ function __get($name) { $this->init(); @@ -128,6 +152,11 @@ } } + /** + * Ustawia zmienną o podanej nazwie + * @param string $name Nazwa zmiennej + * @param mixed $value Wartość zmiennej + */ function __set($name, $value) { $this->init(); @@ -135,6 +164,11 @@ $st->execute(array($this->class, $name, serialize($value))); } + /** + * Sprawdza czy podana zmienna została ustawiona. + * @param string $name Nazwa zmiennej + * @return bool Czy zmienna istnieje? + */ function __isset($name) { $this->init(); @@ -145,6 +179,10 @@ return ($st[0]>0); } + /** + * Usuwa zmienną o podanej nazwie + * @param string $name Nazwa zmiennej + */ function __unset($name) { $this->init(); @@ -152,6 +190,10 @@ $st->execute(array($this->class, $name)); } + /** + * Zapamiętuje tablicę zmiennych danego modułu + * @param array $array Tablica zmiennych + */ function push($array) { $this->PDO->beginTransaction(); foreach($array as $name => $value) { @@ -160,6 +202,10 @@ $this->PDO->commit(); } + /** + * Zwraca wszystkie ustawione zmienne danego modułu + * @return array Lista wszystkich zmiennych + */ function pull() { $this->init(); @@ -169,16 +215,15 @@ $return = array(); foreach($st as $row) { - $return[$row['name']] = $row['value']; + $return[$row['name']] = unserialize($row['value']); } return $return; } - function setClass($class) { - $this->class = $class; - } - + /** + * Usuwa wszystkie zmienne sesyjne danego modułu. + */ function truncate() { $this->init(); diff --git a/class/BotUser.php b/class/BotUser.php index c2b209a..2fe8251 100644 --- a/class/BotUser.php +++ b/class/BotUser.php @@ -9,13 +9,13 @@ * - IMified * - HTTP * - Local - * @var string + * @var string $interface */ private $interface; /** * Numer lub identyfikator użytkownika - * @var string + * @var string $uid */ private $uid; @@ -29,22 +29,30 @@ * - yahoo.imified.com * - gtalk.imified.com * - localhost - * @var string + * @var string $network */ private $network; /** * Identyfikator/unikalna nazwa bota, do którego skierowano zapytanie. * Najczęściej numer Gadu-Gadu lub botkey w przypadku IMified.com + * @var string $bot */ private $bot; /** * Parametry zapytania. Przy IMified równe zmiennej $_POST['channel'] - * @var string + * @var string $params */ private $params; + /** + * Konstruktor. W argumencie otrzymuje pseudo-URL określający użytkownika i sieć. + * Przykłady: + * - Gadu-Gadu://123456\@gadu-gadu.pl + * - IMified://user\\\@jabber\@jabber.imified.com/BOTKEY?private + * @param string $user URL użytkownika + */ function __construct($user) { $data = parse_url($user); @@ -55,6 +63,11 @@ $this->params = @$data['query']; } + /** + * Umożliwia dostęp tylko do odczytu do prywanych zmiennych + * @param string $name Nazwa zmiennej + * @return mixed Wartość zmiennej prywatnej + */ function __get($name) { return $this->$name; } diff --git a/class/legacy/calendar.php b/class/legacy/calendar.php index ca28961..8949144 100644 --- a/class/legacy/calendar.php +++ b/class/legacy/calendar.php @@ -1,12 +1,14 @@ <?php /** + * Klasa obsługująca polskie wyrażenia określające daty * @todo Potrzebna jest funkcja, które będzie wyciągać datę z początku lub końca danego ciągu. Patrz: {@link tv::parse_date()} */ class calendar { /** + * Na podstawie podanej daty zwraca uniksowy znacznik czasu * @param string $date Data w formacie "naturalnym". Np. jutro, 1 stycznia, piątek - * @return int Uniksowy znacznik czasu. Do użycia w funkcji date() - * @uses funcs::utfToAscii() + * @return int Uniksowy znacznik czasu - liczba sekund od północy 1 stycznia 1970 + * @see http://www.php.net/date */ static function parse_date($date) { $date = funcs::utfToAscii($date); diff --git a/class/legacy/funcs.php b/class/legacy/funcs.php index 492e1e4..fe28ad3 100644 --- a/class/legacy/funcs.php +++ b/class/legacy/funcs.php @@ -2,13 +2,24 @@ class BotLegacyEnd extends Exception {} class funcs { + /** + * Przerywa dalsze wykonywanie modułu i wysyła odpowiedź do klienta + * @deprecated Przestarzałe wraz z wprowadzeniem nowego API. + * Metoda może zostać usunięta bez ostrzeżenia! + */ static function end() { throw new BotLegacyEnd(); } + /** + * Funkcja usuwa "ogonki" (transliteracja), podwójne spacje i odstępy + * z podanego w parametrze ciągu znaków oraz zamienia wszystkie litery na małe + * @param string $utf Ciąg znaków w UTF-8 + * @returns string Ciąg po przetworzeniu + */ static function utfToAscii($utf) { $utf = trim(str_replace(' ', ' ', $utf)); - return strtolower(iconv('utf-8', 'ascii//TRANSLIT', trim($utf))); + return strtolower(iconv('utf-8', 'ascii//TRANSLIT', $utf)); } } ?> \ No newline at end of file diff --git a/class/legacy/jsarray.php b/class/legacy/jsarray.php index a3b952d..9961de6 100644 --- a/class/legacy/jsarray.php +++ b/class/legacy/jsarray.php @@ -11,8 +11,11 @@ // Ignore < ? php and ? > added above if($token[0] == T_OPEN_TAG OR $token[0] == T_CLOSE_TAG) continue; // String/int element within an array - if($token[0] == T_CONSTANT_ENCAPSED_STRING || $token[0] == T_LNUMBER) { + if($token[0] == T_CONSTANT_ENCAPSED_STRING) { $element = substr($token[1], 1, -1); + } + if($token[0] == T_LNUMBER) { + $element = $token[1]; } } // Nested array @@ -21,7 +24,7 @@ } // End of nested array elseif($token == ']') { - // Put elements into the lastest array + // Put elements into the latest array if($element !== NULL && $element !== FALSE) { end($stack); $stack[key($stack)][] = $element; @@ -38,7 +41,7 @@ } // Elements separator elseif($token == ',') { - // Put elements into the lastest array (]] check) + // Put elements into the latest array (]] check) if($element !== FALSE) { end($stack); $stack[key($stack)][] = $element; @@ -47,11 +50,15 @@ } else { - return array(); + return FALSE; } } - return $stack[0][0]; + if(isset($stack[0][0])) { + return $stack[0][0]; + } else { + return NULL; + } } } ?> \ No newline at end of file diff --git a/class/legacy/main.php b/class/legacy/main.php index 6949a5d..fe6137d 100644 --- a/class/legacy/main.php +++ b/class/legacy/main.php @@ -1,6 +1,12 @@ <?php class main { - const VERSION = '2.5'; - const VERSION_NUM = '2.5'; + /** + * Wersja bota w formacie: <i>X.Y TYPE</i>, np. <i>2.0 Beta</i> + */ + const VERSION = '2.6'; + /** + * Wersja bota, tylko część numeryczna (X.Y), np. <i>2.0</i> + */ + const VERSION_NUM = '2.6'; } ?> diff --git a/class/legacy/module.php b/class/legacy/module.php index d089256..f1b91df 100644 --- a/class/legacy/module.php +++ b/class/legacy/module.php @@ -1,18 +1,19 @@ <?php interface module { static function register_cmd(); - // Returns: + // Zwraca: // array( - // 'CMD1_NAME' => 'FUNCTION_INSIDE_CLASS', - // 'CMD2_NAME' => 'FUNCTION_INSIDE_CLASS', + // 'KOMENDA1' => 'METODA_OBSLUGUJACA_KOMENDE1', + // 'KOMENDA2' => 'METODA_OBSLUGUJACA_KOMENDE2', // ... // ) static function help($cmd=NULL); - // Return help content about command $cmd to GGapi::put*() functions - // if $cmd is NULL return help content for all commands + // Zwraca pomoc dotyczącą komendy z użyciem funkcji GGapi::put*() + // Jeśli $cmd === NULL, zwraca skróconą listę poleceń modułu - // static function FUNCTION_INSIDE_CLASS(CMD_NAME, REST_OF_PLAINTEXT) - // REST_OF_PLAINTEXT is raw (non trimmed etc.) part after command name, without leading space + // static function METODA_OBSLUGUJACA_KOMENDE(NAZWA_KOMENDY, ARGUMENTY) + // ARGUMENTY to wszystko poza nazwą komendy, przekazane w taki sposób, + // w jaki zostały otrzymane od użytkownika } ?> \ No newline at end of file diff --git a/class/std.php b/class/std.php index c173cd5..1f5c246 100644 --- a/class/std.php +++ b/class/std.php @@ -30,11 +30,13 @@ throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } -error_reporting(E_COMPILE_ERROR|E_PARSE); +if(!defined('PHPUNIT')) { + error_reporting(E_COMPILE_ERROR|E_PARSE); + set_error_handler('errorToException', E_ALL & ~E_NOTICE); +} setlocale(LC_CTYPE, 'pl_PL.utf8', 'pl_PL', 'polish', 'plk'); mb_internal_encoding('UTF-8'); libxml_use_internal_errors(); spl_autoload_register('botAutoload'); -set_error_handler('errorToException', E_ALL & ~E_NOTICE); ?> \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..243c123 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,10 @@ +<phpunit bootstrap="tests/autoload.php"> + <php> + <const name="PHPUNIT" value="true" /> + </php> + <testsuites> + <testsuite name="Core Test Suite"> + <directory suffix="Test.php">tests/Core</directory> + </testsuite> + </testsuites> +</phpunit> diff --git a/tests/Core/BotMessageTest.php b/tests/Core/BotMessageTest.php new file mode 100644 index 0000000..93195c7 --- /dev/null +++ b/tests/Core/BotMessageTest.php @@ -0,0 +1,13 @@ +<?php +class BotMessageTest extends PHPUnit_Framework_TestCase { + function testAppend() { + $input = ' ąęß śćżń óó '; + $message = new BotMessage(); + $message->setText($input); + + $this->assertEquals($input, $message->rawText); + $this->assertEquals('aess sczn oo', $message->text); + $this->assertEquals('aess', $message->command); + $this->assertEquals('śćżń óó', $message->args); + } +} diff --git a/tests/Core/BotMsgTest.php b/tests/Core/BotMsgTest.php new file mode 100644 index 0000000..36f4fe5 --- /dev/null +++ b/tests/Core/BotMsgTest.php @@ -0,0 +1,99 @@ +<?php +class BotMsgTest extends PHPUnit_Framework_TestCase { + function testAppend() { + $text = ''; + + $substring = 'abc'; + $msg = new BotMsg($substring); + $text .= $substring; + + $substring = 'cba'; + $msg->a($substring); + $text .= $substring; + + $substring = 'cba'; + $msg->append($substring); + $text .= $substring; + + $this->assertEquals($text, $msg->getRaw()); + } + + function testBeautifilText() { + $msg = new BotMsg('<h1>Test</h1><p><u><i>This.</i></u></p><p><b>That!</b></p>'); + $expect = '= Test ='."\n" + .'_/This./_'."\n\n" + .'*That!*'; + $msg->setBeautiful(TRUE); + $this->assertEquals($expect, $msg->getText()); + + $expect = 'Test'."\n" + .'This.'."\n\n" + .'That!'; + $msg->setBeautiful(FALSE); + $this->assertEquals($expect, $msg->getText()); + + } + + function testGetText() { + $msg = new BotMsg('<h2>Test</h2>'."\n" + .'<h3>Test h3</h3>'."\n" + .'<p><a href="http://jacekk.info">http://jacekk.info</a><br />'."\n" + .'<a href="http://jacekk.info">Jacekk.info</a></p>'); + $expect = '== Test =='."\n" + .'=== Test h3 ==='."\n" + .'http://jacekk.info'."\n" + .'Jacekk.info (http://jacekk.info)'; + $this->assertEquals($expect, $msg->getText()); + + $msg = new BotMsg('<table>'."\n" + .'<tr><th>Header 1</th> <th>Header 2</th></tr>'."\n" + .'<tr><td>Cell 1</td> <td>Cell 2<img src="" /></td></tr>'."\n" + .'</table>'); + $expect = '*Header 1* *Header 2*'."\n" + .'Cell 1 Cell 2'; + $this->assertEquals($expect, $msg->getText()); + + $msg = new BotMsg('<h3>Test h3</h3>abc<p>Test</p>'); + $expect = '=== Test h3 ==='."\n" + .'abc'."\n\n" + .'Test'; + $this->assertEquals($expect, $msg->getText()); + } + + function testGetHTML() { + $msg = new BotMsg('<h1>Test</h1>'."\n" + .'<p><u><i>This.</i></u></p>'."\n" + .'<p><b color="#fff">That!</b></p>'."\n" + .'<p><a>http://jacekk.info</a></p>'); + $expect = '<h1>Test</h1>'."\n" + .'<p><u><i>This.</i></u></p>'."\n" + .'<p><b style="color:#fff;">That!</b></p>'."\n" + .'<p><a href="http://jacekk.info">http://jacekk.info</a></p>'; + + $this->assertEquals($expect, $msg->getHTML()); + $this->assertEquals($expect, (string)$msg); + } + + function testHTMLError() { + $oldhandler = set_error_handler('errorToException'); + + $msg = new BotMsg('<![CDATA[ <p></p> ]]>'); + $msg->getHTML(); + + set_error_handler($oldhandler); + } + + function testSleep() { + $msg = new BotMsg('<h1>Test</h1><p><u><i>This.</i></u></p><p><b>That!</b></p>'); + $raw = $msg->getRaw(); + $text = $msg->getText(); + $html = $msg->getHTML(); + + $serialized = serialize($msg); + $msg = unserialize($serialized); + + $this->assertEquals($raw, $msg->getRaw()); + $this->assertEquals($text, $msg->getText()); + $this->assertEquals($html, $msg->getHTML()); + } +} diff --git a/tests/Core/BotSessionTest.php b/tests/Core/BotSessionTest.php new file mode 100644 index 0000000..1b2209f --- /dev/null +++ b/tests/Core/BotSessionTest.php @@ -0,0 +1,136 @@ +<?php +class BotSessionTest extends PHPUnit_Framework_TestCase { + function testSessionFolder() { + $dbFolder = dirname(__FILE__).'/../../database'; + + $this->assertTrue(is_writable($dbFolder)); + $this->assertTrue(count(glob($dbFolder.'/*.sqlite')) == 0); + } + + /** + * @depends testSessionFolder + */ + function testPullEmpty() { + $dbFolder = dirname(__FILE__).'/../../database'; + + $session = new BotSession('test://user1@test'); + $session->setClass('test'); + + $this->assertEquals(array(), $session->pull()); + $this->assertTrue(count(glob($dbFolder.'/*.sqlite')) == 1); + } + + /** + * @depends testPullEmpty + * @expectedException Exception + */ + function testSetClass() { + $session = new BotSession('test://user1'); + $session->pull(); + } + + /** + * @depends testPullEmpty + */ + function testLegacyImport() { + $dbFolder = dirname(__FILE__).'/../../database'; + $oldDbFolder = $dbFolder = dirname(__FILE__).'/../../db'; + + $data = array('test' => true, 'other' => 'yes, sir!'); + $data_serialized = serialize($data); + + $this->assertTrue(mkdir($oldDbFolder)); + $this->assertTrue(is_writable($oldDbFolder)); + $this->assertTrue(mkdir($oldDbFolder.'/test')); + + $filename = $oldDbFolder.'/test/testUser.ggdb'; + $this->assertEquals(strlen($data_serialized), file_put_contents($filename, $data_serialized)); + $this->assertEquals($data_serialized, file_get_contents($filename)); + + $session = new BotSession('test://testUser@test'); + $session->setClass('test'); + + $this->assertTrue(isset($session->test)); + $this->assertEquals($data, $session->pull()); + + $this->assertFalse(file_exists($filename)); + $this->assertTrue(rmdir($oldDbFolder.'/test')); + $this->assertTrue(rmdir($oldDbFolder)); + } + + /** + * @depends testPullEmpty + */ + function testManualExample() { + $session = new BotSession('test://user1@test'); + $session->setClass('test'); + + // Ustawienie pojedynczej wartości + $session->zmienna = 'To jest test'; + $this->assertTrue(isset($session->zmienna)); + $this->assertEquals('To jest test', $session->zmienna); + + // Usunięcie pojedynczej wartości + unset($session->zmienna); + $this->assertFalse(isset($session->zmienna)); + $this->assertEquals(NULL, $session->zmienna); + + // Ustawienie pojedynczej wartości ponownie + $session->zmienna = 'To jest test'; + $this->assertTrue(isset($session->zmienna)); + $this->assertEquals('To jest test', $session->zmienna); + + // Usunięcie wszystkich danych + $session->truncate(); + $this->assertFalse(isset($session->zmienna)); + $this->assertEquals(NULL, $session->zmienna); + $this->assertEquals(array(), $session->pull()); + + // Dopisanie (nadpisanie) danych + $array = array( + 'zmienna' => 'To jest test2', + 'zmienna2' => new DateTime('2012-01-10') + ); + $session->push($array); + + $this->assertEquals('To jest test2', $session->zmienna); + $this->assertEquals($array, $session->pull()); + + // push() nie usuwa istniejących danych + $session->zmienna3 = '333'; + $session->push($array); + $this->assertNotEquals($array, $session->pull()); + + unset($this->session); + } + + /** + * @depends testManualExample + */ + function testManualExample2() { + $session = new BotSession('test://user1@test'); + $session->setClass('test'); + + $array = array( + 'zmienna' => 'To jest test2', + 'zmienna2' => new DateTime('2012-01-10'), + 'zmienna3' => '333' + ); + + $this->assertEquals($array, $session->pull()); + + + $session->setClass('test2'); + $this->assertEquals(array(), $session->pull()); + } + + /** + * @depends testManualExample2 + */ + function testCleanup() { + $dbFolder = dirname(__FILE__).'/../../database'; + foreach(glob($dbFolder.'/*.sqlite') as $file) { + unlink($file); + } + } +} diff --git a/tests/Core/Legacy/JSArrayTest.php b/tests/Core/Legacy/JSArrayTest.php new file mode 100644 index 0000000..f957afe --- /dev/null +++ b/tests/Core/Legacy/JSArrayTest.php @@ -0,0 +1,29 @@ +<?php +class JSArrayTest extends PHPUnit_Framework_TestCase { + public function testEmptyString() { + $result = jsarray::parse(''); + $this->assertSame(NULL, $result); + } + + public function testEmptyArray() { + $result = jsarray::parse('[]'); + $this->assertEquals(array(), $result); + } + + public function testNestedArrays() { + $array = array( + array(1, 2, array(), 5, array(6, array(7, 8))), + array(9), + '10' + ); + $array_js = json_encode($array); + $array_decoded = jsarray::parse($array_js); + + $this->assertEquals($array, $array_decoded); + } + + public function testInvalid() { + $result = jsarray::parse('()'); + $this->assertSame(FALSE, $result); + } +} diff --git a/tests/autoload.php b/tests/autoload.php new file mode 100644 index 0000000..dfeb740 --- /dev/null +++ b/tests/autoload.php @@ -0,0 +1,2 @@ +<?php +require_once(dirname(__FILE__).'/../class/std.php'); -- Gitblit v1.9.1