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