[limb-svn] r5797 - in 3.x/trunk/limb/macro: src tests/cases

svn at limb-project.com svn at limb-project.com
Fri May 4 02:28:03 MSD 2007


Author: pachanga
Date: 2007-05-04 02:28:03 +0400 (Fri, 04 May 2007)
New Revision: 5797
URL: http://fisheye.limb-project.com/changelog/limb/?cs=5797

Added:
   3.x/trunk/limb/macro/src/lmbMacroCodeWriter.class.php
   3.x/trunk/limb/macro/src/lmbMacroException.class.php
   3.x/trunk/limb/macro/src/lmbMacroNode.class.php
   3.x/trunk/limb/macro/src/lmbMacroTag.class.php
   3.x/trunk/limb/macro/src/lmbMacroTagInfo.class.php
   3.x/trunk/limb/macro/tests/cases/lmbMacroTagTest.class.php
Log:
-- adding initial versions of lmbMacroCodeWriter, lmbMacroException, lmbMacroNode, lmbMacroTag, lmbMacroTagInfo

Added: 3.x/trunk/limb/macro/src/lmbMacroCodeWriter.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroCodeWriter.class.php	                        (rev 0)
+++ 3.x/trunk/limb/macro/src/lmbMacroCodeWriter.class.php	2007-05-03 22:28:03 UTC (rev 5797)
@@ -0,0 +1,176 @@
+<?php
+/**
+ * Limb Web Application Framework
+ *
+ * @link http://limb-project.com
+ *
+ * @copyright  Copyright &copy; 2004-2007 BIT
+ * @license    LGPL http://www.gnu.org/copyleft/lesser.html
+ * @version    $Id: WactCodeWriter.class.php 5071 2007-02-16 09:09:35Z serega $
+ * @package    macro
+ */
+
+class lmbMacroCodeWriter
+{
+  const MODE_PHP = 1;
+  const MODE_HTML = 2;
+
+  protected $current_mode = self :: MODE_HTML;
+
+  protected $code = '';
+
+  protected $function_prefix = '';
+  protected $function_suffix = 1;
+
+  protected $include_list = array();
+
+  protected $tempVarName = 1;
+
+  function reset()
+  {
+    $this->code = '';
+    $this->current_mode = self :: MODE_HTML;
+    $this->include_list = array();
+  }
+
+  protected function switchToPHP()
+  {
+    if($this->current_mode == self :: MODE_HTML)
+    {
+      $this->current_mode = self :: MODE_PHP;
+      $this->code .= '<?php ';
+    }
+  }
+
+  protected function switchToHTML($context = null)
+  {
+    if($this->current_mode == self :: MODE_PHP)
+    {
+      $this->current_mode = self :: MODE_HTML;
+      if($context === "\n")
+        $this->code .= " ?>\n";
+      else
+        $this->code .= ' ?>';
+    }
+  }
+
+  function writePHP($text)
+  {
+    $this->switchToPHP();
+    $this->code .= $text;
+  }
+
+  function writePHPLiteral($text, $escape_text = true)
+  {
+    $this->switchToPHP();
+
+    if($escape_text)
+      $this->code .= "'" . $this->escapeLiteral($text) . "'";
+    else
+      $this->code .= "'" . $text . "'";
+  }
+
+  function escapeLiteral($text)
+  {
+    $text = str_replace('\'', "\\'", $text);
+    if(substr($text, -1) == '\\')
+      $text .= '\\';
+    return $text;
+  }
+
+  function writeHTML($text)
+  {
+    $this->switchToHTML(substr($text,0,1));
+    $this->code .= $text;
+  }
+
+  function renderCode()
+  {
+    $this->switchToHTML();
+
+    $this->_prependIncludeListToCode();
+
+    return $this->code;
+  }
+
+  function getCode()
+  {
+    return $this->code;
+  }
+
+  function setCode($code)
+  {
+    $this->code = $code;
+  }
+
+  protected function _prependIncludeListToCode()
+  {
+    $include_code = '';
+    foreach($this->include_list as $include_file)
+      $include_code .= "require_once('$include_file');\n";
+
+    if(!empty($include_code))
+      $this->code = '<?php ' . $include_code . '?>' . $this->code;
+  }
+
+  function getMode()
+  {
+    return $this->current_mode;
+  }
+
+  function registerInclude($include_file)
+  {
+    if(!in_array($include_file, $this->include_list))
+      $this->include_list[] = $include_file;    
+  }
+
+  function getIncludeList()
+  {
+    return $this->include_list;
+  }
+
+  /**
+  * Begins writing a PHP function to the compiled template, using the
+  * function_prefix and the function_suffix, the latter being post incremented
+  * by one.
+  */
+  function beginFunction($param_list)
+  {
+      $func_name = 'tpl' . $this->function_prefix . $this->function_suffix++;
+      $this->writePHP('function ' . $func_name . $param_list ." {\n");
+      return $func_name;
+  }
+
+  function endFunction()
+  {
+    $this->writePHP(" }\n");
+  }
+
+  function setFunctionPrefix($prefix)
+  {
+    $this->function_prefix = $prefix;
+  }
+
+  /**
+  * Utility method, which generates a unique variable name
+  */
+  function getTempVariable()
+  {
+    $var = $this->tempVarName++;
+    if($var > 675)
+      return chr(65 + ($var/26)/26) . chr(65 + ($var/26)%26) . chr(65 + $var%26);
+    elseif($var > 26)
+      return chr(65 + ($var/26)%26) . chr(65 + $var%26);
+    else
+      return chr(64 + $var);
+  }
+
+  /**
+  * Utility method, which generates a unique variable name, prefixed with a $
+  */
+  function getTempVarRef()
+  {
+    return '$' . $this->getTempVariable();
+  }
+}
+?>

Added: 3.x/trunk/limb/macro/src/lmbMacroException.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroException.class.php	                        (rev 0)
+++ 3.x/trunk/limb/macro/src/lmbMacroException.class.php	2007-05-03 22:28:03 UTC (rev 5797)
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Limb Web Application Framework
+ *
+ * @link http://limb-project.com
+ *
+ * @copyright  Copyright &copy; 2004-2007 BIT
+ * @license    LGPL http://www.gnu.org/copyleft/lesser.html
+ * @version    $Id: error.inc.php 5334 2007-03-23 11:48:20Z pachanga $
+ * @package    macro
+ */
+
+class lmbMacroException extends lmbException
+{
+  function __construct($message, $params = array())
+  {
+    parent :: __construct('MACRO exception: ' . $message, $params);
+  }
+}
+?>
\ No newline at end of file

Added: 3.x/trunk/limb/macro/src/lmbMacroNode.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroNode.class.php	                        (rev 0)
+++ 3.x/trunk/limb/macro/src/lmbMacroNode.class.php	2007-05-03 22:28:03 UTC (rev 5797)
@@ -0,0 +1,245 @@
+<?php
+/**
+ * Limb Web Application Framework
+ *
+ * @link http://limb-project.com
+ *
+ * @copyright  Copyright &copy; 2004-2007 BIT
+ * @license    LGPL http://www.gnu.org/copyleft/lesser.html
+ * @version    $Id: WactCompilerTag.class.php 5203 2007-03-07 08:58:21Z serega $
+ * @package    macro
+ */
+lmb_require('limb/macro/src/lmbMacroException.class.php');
+lmb_require('limb/macro/src/lmbMacroSourceLocation.class.php');
+
+class lmbMacroNode
+{
+  protected $id;  
+  protected $children = array();
+  protected $parent;  
+  /**
+  * @var lmbMacroSourceLocation
+  **/
+  protected $location;    
+
+  function __construct($location = null)
+  {
+    if($location)
+      $this->location = $location;
+    else
+      $this->location = new lmbMacroSourceLocation();
+  }
+  
+  function setParent($parent)
+  {
+    $this->parent = $parent;
+  }
+  
+  function getLocationInTemplate()
+  {
+    return $this->location;
+  }
+
+  function getTemplateFile()
+  {
+    return $this->location->getFile();
+  }
+
+  function getTemplateLine()
+  {
+    return $this->location->getLine();
+  }
+
+  function getId()
+  {
+    if($this->id)
+      return $this->id;
+        
+    $this->id = self :: generateNewId();
+    return $this->id;
+  }
+
+  function setId($id)
+  {
+    $this->id = $id;
+  }  
+  
+  static function generateNewId()
+  {
+    static $counter = 1;
+    return 'id00' . $counter++;
+  }    
+  
+  function raise($error, $vars = array())
+  {    
+    $vars['file'] = $this->location->getFile();
+    $vars['line'] = $this->location->getLine();
+    throw new lmbMacroException($error, $vars);
+  }  
+  
+  function addChild($child)
+  {
+    $child->parent = $this;
+    $this->children[] = $child;
+  }
+
+  function removeChild($id)
+  {
+    foreach(array_keys($this->children) as $key)
+    {
+      $child = $this->children[$key];
+      if($child->getId() == $id)
+      {
+        unset($this->children[$key]);
+        return $child;
+      }
+    }
+  }
+
+  function getChildren()
+  {
+    return $this->children;
+  }
+
+  function removeChildren()
+  {
+    foreach (array_keys($this->children) as $key)
+    {
+      $this->children[$key]->removeChildren();
+      unset($this->children[$key]);
+    }
+  }
+
+  function getChild($id)
+  {
+    if($child = $this->findChild($id))
+      return $child;
+    else
+      $this->raise('Could not find component', array('id' => $id));
+  }
+
+  function findChild($id)
+  {
+    foreach(array_keys($this->children) as $key)
+    {
+      if($this->children[$key]->getId() == $id)
+        return $this->children[$key];
+      else
+        return $this->children[$key]->findChild($id);          
+    }
+  }
+
+  function findChildByClass($class)
+  {
+    foreach(array_keys($this->children) as $key)
+    {
+      if(is_a($this->children[$key], $class))
+        return $this->children[$key];
+      else
+      {
+        if($result = $this->children[$key]->findChildByClass($class))
+          return $result;
+      }
+    }
+  }
+
+  function findChildrenByClass($class)
+  {
+    $ret = array();
+    foreach(array_keys($this->children) as $key)
+    {
+      if(is_a($this->children[$key], $class))
+        $ret[] = $this->children[$key];
+      else
+      {
+        $more_children = $this->children[$key]->findChildrenByClass($class);
+        if(count($more_children))
+          $ret = array_merge($ret, $more_children);
+      }
+    }
+    return $ret;
+  }
+
+  function findImmediateChildByClass($class)
+  {
+    foreach(array_keys($this->children) as $key)
+    {
+      if(is_a($this->children[$key], $class))
+        return $this->children[$key];
+    }
+  }
+
+  function findImmediateChildrenByClass($class)
+  {
+    $result = array();
+    foreach(array_keys($this->children) as $key)
+    {
+      if(is_a($this->children[$key], $class))
+        $result[] = $this->children[$key];
+    }
+    return $result;
+  }  
+  
+  function findParentByClass($class)
+  {
+    $parent = $this->parent;
+
+    while($parent && !is_a($parent, $class))
+      $parent = $parent->parent;
+
+    return $parent;
+  }  
+  
+  function prepare()
+  {
+    foreach(array_keys($this->children) as $key)
+      $this->children[$key]->prepare();
+  }  
+
+  function preParse(){}
+  
+  function generateConstructor($code_writer)
+  {
+    foreach(array_keys($this->children) as $key)
+      $this->children[$key]->generateConstructor($code_writer);
+  }
+
+  function generateContents($code_writer)
+  {
+    foreach(array_keys($this->children) as $key)
+      $this->children[$key]->generate($code_writer);
+  }
+  
+  function generate($code_writer)
+  {   
+    $this->generateContents($code_writer);   
+  }  
+     
+  /**
+  * Checks that each immediate child of the current component has a unique ID
+  * amongst its siblings.
+  */
+  function checkChildrenIds()
+  {
+    $child_ids = array();
+    $checked_children = array();
+    foreach($this->getChildren() as $key => $child)
+    {
+      $id = $child->getId();
+      if (in_array($id, $child_ids))
+      {
+        $duplicate_child = $checked_children[$id];
+        $child->raise('Duplicate "id" attribute',
+                                   array('id' => $id,
+                                         'duplicate_node_file' => $duplicate_child->getTemplateFile(),
+                                         'duplicate_node_line' => $duplicate_child->getTemplateLine()));
+      }
+      else
+      {
+        $child_ids[] = $id;
+        $checked_children[$id] = $child;
+      }
+    }
+  }  
+}
+?>
\ No newline at end of file

Added: 3.x/trunk/limb/macro/src/lmbMacroTag.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTag.class.php	                        (rev 0)
+++ 3.x/trunk/limb/macro/src/lmbMacroTag.class.php	2007-05-03 22:28:03 UTC (rev 5797)
@@ -0,0 +1,134 @@
+<?php
+/**
+ * Limb Web Application Framework
+ *
+ * @link http://limb-project.com
+ *
+ * @copyright  Copyright &copy; 2004-2007 BIT
+ * @license    LGPL http://www.gnu.org/copyleft/lesser.html
+ * @version    $Id: WactCompilerTag.class.php 5203 2007-03-07 08:58:21Z serega $
+ * @package    macro
+ */
+
+lmb_require('limb/macro/src/lmbMacroNode.class.php');
+
+class lmbMacroTag extends lmbMacroNode
+{
+  protected $tag;
+  protected $has_closing_tag = true;
+  protected $empty_closed_tag = false;  
+  protected $tag_info;
+  protected $attributes = array();
+  
+  function __construct($location, $tag, $tag_info)
+  {
+    $this->tag = $tag;
+    $this->tag_info = $tag_info;
+    
+    parent :: __construct($location);
+  }
+
+  function getTag()
+  {
+    return $this->tag;
+  }
+  
+  function getId()
+  {
+    if($this->id)
+      return $this->id;
+        
+    if($id = $this->get('id'))
+      $this->id = $id;
+    else
+      $this->id = self :: generateNewId();
+
+    return $this->id;
+  }  
+  
+  function get($name)
+  {
+    if(array_key_exists(strtolower($name), $this->attributes))
+      return $this->attributes[strtolower($name)];
+  }  
+  
+  function set($name, $value)
+  {
+    $this->attributes[strtolower($name)] = $value;
+  }
+
+  function has($name)
+  {
+    return array_key_exists(strtolower($name), $this->attributes);
+  }
+
+  /**
+  * Return the value of a boolean attribute as a boolean.
+  * ATTRIBUTE=ANYTHING  (true)
+  * ATTRIBUTE=(false|N|NA|NO|NONE|0) (false)
+  * ATTRIBUTE (true)
+  * (attribute unspecified) (default)
+  */
+  function getBool($attrib, $default = false)
+  {
+    if(!isset($this->attributes[strtolower($attrib)]))
+      return $default;
+
+    return self :: getBooleanValue($this->attributes[strtolower($attrib)]);
+  }
+
+  static function getBooleanValue($value)
+  {
+    switch(strtoupper($value))
+    {
+      case 'FALSE':
+      case 'N':
+      case 'NO':
+      case 'NONE':
+      case 'NA':
+      case '0':
+        return false;
+      default:
+        return true;
+    }
+  }
+
+  function remove($attrib)
+  {
+    unset($this->attributes[strtolower($attrib)]);
+  }  
+    
+  function raise($error, $vars = array())
+  {
+    $vars['tag'] = $this->tag;
+    parent :: raise($error, $vars);
+  }  
+
+  function raiseRequiredAttribute($attribute_name)
+  {
+    $this->raise('Missing required attribute', array('attribute' => $attribute_name));
+  }
+  
+  function preParse()
+  {
+    foreach($this->tag_info->getRequiredAttributes() as $attr_name)
+    {
+      if(!$this->has($attr_name))
+        $this->raiseRequiredAttribute($attr_name);
+    }
+
+    if($this->tag_info->isRestrictSelfNesting() && $parent = $this->findParentByClass(get_class($this)))
+      $this->raise('Tag cannot be nested within the same tag',
+                                array('same_tag_file' => $parent->getTemplateFile(),
+                                      'same_tag_line' => $parent->getTemplateLine()));
+
+    if(($parent_class = $this->tag_info->getParentClass()) &&
+       !$parent = $this->findParentByClass($parent_class))
+    {
+      $this->raise('Tag must be enclosed by a proper parent tag',
+                                array('required_parent_tag_class' => $parent_class));
+
+    }
+  }  
+}
+?>
\ No newline at end of file

Added: 3.x/trunk/limb/macro/src/lmbMacroTagInfo.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTagInfo.class.php	                        (rev 0)
+++ 3.x/trunk/limb/macro/src/lmbMacroTagInfo.class.php	2007-05-03 22:28:03 UTC (rev 5797)
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Limb Web Application Framework
+ *
+ * @link http://limb-project.com
+ *
+ * @copyright  Copyright &copy; 2004-2007 BIT
+ * @license    LGPL http://www.gnu.org/copyleft/lesser.html
+ * @version    $Id: WacttagInfo.class.php 5021 2007-02-12 13:04:07Z pachanga $
+ * @package    macro
+ */
+
+class lmbMacroTagInfo
+{
+  protected $tag = '';
+  protected $class = '';
+  protected $file;
+  protected $req_attributes = array();
+  protected $parent_class;
+  protected $restrict_self_nesting = false;
+  protected $forbid_parsing = false;
+  protected $forbid_endtag = false;
+
+  function __construct($tag, $class)
+  {
+    $this->tag = $tag;
+    $this->class = $class;
+  }
+
+  function setForbidEndtag($flag = true)
+  {
+    $this->forbid_endtag = $flag;
+  }
+
+  function isEndtagForbidden()
+  {
+    return $this->forbid_endtag;
+  }
+
+  function setRequiredAttributes($attributes)
+  {
+    $this->req_attributes = $attributes;
+  }
+
+  function getRequiredAttributes()
+  {
+    return $this->req_attributes;
+  }
+
+  function setParentClass($parent_tag_class)
+  {
+    $this->parent_class = $parent_tag_class;
+  }
+
+  function getParentClass()
+  {
+    return $this->parent_class;
+  }
+
+  function setRestrictSelfNesting($flag = true)
+  {
+    $this->restrict_self_nesting = $flag;
+  }
+
+  function isRestrictSelfNesting()
+  {
+    return $this->restrict_self_nesting;
+  }
+
+  function setForbidParsing($flag = true)
+  {
+    $this->forbid_parsing = $flag;
+  }
+
+  function isParsingForbidden()
+  {
+    return $this->forbid_parsing;
+  }
+
+  function load()
+  {
+    if(!class_exists($this->class) && isset($this->file))
+      require_once($this->file);
+  }
+}
+?>
\ No newline at end of file

Added: 3.x/trunk/limb/macro/tests/cases/lmbMacroTagTest.class.php
===================================================================
--- 3.x/trunk/limb/macro/tests/cases/lmbMacroTagTest.class.php	                        (rev 0)
+++ 3.x/trunk/limb/macro/tests/cases/lmbMacroTagTest.class.php	2007-05-03 22:28:03 UTC (rev 5797)
@@ -0,0 +1,355 @@
+<?php
+/**
+ * Limb Web Application Framework
+ *
+ * @link http://limb-project.com
+ *
+ * @copyright  Copyright &copy; 2004-2007 BIT
+ * @license    LGPL http://www.gnu.org/copyleft/lesser.html
+ * @version    $Id: lmbMacroTagTest.class.php 5021 2007-02-12 13:04:07Z pachanga $
+ * @package    macro
+ */
+
+lmb_require('limb/macro/src/lmbMacroNode.class.php'); 
+lmb_require('limb/macro/src/lmbMacroTag.class.php');
+lmb_require('limb/macro/src/lmbMacroTagInfo.class.php');
+lmb_require('limb/macro/src/lmbMacroSourceLocation.class.php');
+lmb_require('limb/macro/src/lmbMacroCodeWriter.class.php'); 
+ 
+class MacroTagClass1CompilerTest extends lmbMacroTag{}
+class MacroTagClass2CompilerTest extends lmbMacroTag{}
+
+Mock::generate('lmbMacroNode', 'MockMacroNode');
+Mock::generate('lmbMacroCodeWriter', 'MockMacroCodeWriter');
+
+class lmbMacroTagTest extends UnitTestCase
+{
+  protected $node;
+  protected $tag_info;
+  protected $source_location;
+
+  function setUp()
+  {
+    $this->tag_info = new lmbMacroTagInfo('MacroTag', 'whatever');
+    $this->source_location = new lmbMacroSourceLocation('my_file', 10);
+    $this->node = $this->_createNode();
+  }
+
+  protected function _createNode()
+  {
+    return new lmbMacroTag($this->source_location, 'my_tag', $this->tag_info);
+  }
+  
+  function testGetIdAttribute()
+  {
+    $this->node->setId('Test');
+    $this->assertEqual($this->node->getId(), 'Test');
+  }
+
+  function testGetIdGenerated()
+  {
+    $id = $this->node->getId();
+    $this->assertEqual($this->node->getId(), $id);
+  }
+
+  function testFindChild()
+  {
+    $mock = new MockMacroNode();
+    $mock->setReturnValue('getId', 'Test');
+    $this->node->addChild($mock);
+    $this->assertIsA($this->node->findChild('Test'), 'MockMacroNode');
+  }
+
+  function testFindChildNotFound()
+  {
+    $this->assertFalse($this->node->findChild('Test'));
+  }
+
+  function testFindChildByClass()
+  {
+    $mock = new MockMacroNode();
+    $this->node->addChild($mock);
+    $this->assertIsA($this->node->findChildByClass('MockMacroNode'), 'MockMacroNode');
+  }
+
+  function testFindChildByClassNotFound()
+  {
+    $this->assertFalse($this->node->findChildByClass('Booo'));
+  }
+
+  function testFindParentByChilld()
+  {
+    $parent = new lmbMacroNode;
+    $parent->addChild($this->node);
+    $this->assertIsA($this->node->findParentByClass('lmbMacroNode'), 'lmbMacroNode');
+  }
+
+  function testFindParentByClassNotFound()
+  {
+    $this->assertFalse($this->node->findParentByClass('Test'));
+  }
+
+  function testRemoveChild()
+  {
+    $mock = new MockMacroNode();
+    $mock->setReturnValue('getId', 'Test');
+    $this->node->addChild($mock);
+    $this->assertIsA($this->node->removeChild('Test'), 'MockMacroNode');
+  }
+
+  function testGetChildren()
+  {
+    $mock = new MockMacroNode();
+    $this->node->addChild($mock);
+    $children = $this->node->getChildren();
+    $this->assertReference($mock, $children[0]);
+  }
+
+  function testPrepare()
+  {
+    $child = new MockMacroNode();
+    $this->node->addChild($child);
+    $child->expectCallCount('prepare', 1);
+    $this->node->prepare();
+  }
+
+  function testGenerateConstructor()
+  {
+    $code_writer = new MockMacroCodeWriter();
+    $child = new MockMacroNode();
+    $child->expectCallCount('generateConstructor', 1);
+    $this->node->addChild($child);
+    $this->node->generateConstructor($code_writer);
+  }
+
+  function testGenerateContents()
+  {
+    $code_writer = new MockMacroCodeWriter();
+    $child = new MockMacroNode();
+    $child->expectCallCount('generate', 1);
+    $this->node->addChild($child);
+    $this->node->generateContents($code_writer);
+  }
+
+  function testGenerate()
+  {
+    $code_writer = new MockMacroCodeWriter();
+    $child = new MockMacroNode();
+    $child->expectCallCount('generate', 1);
+    $this->node->addChild($child);
+    $this->node->generate($code_writer);
+  }
+
+  function testCheckIdsOk()
+  {
+    $root = new lmbMacroNode;
+    $child1 = new lmbMacroNode;
+    $child1->setId('id1');
+
+    $child2 = new lmbMacroNode;
+    $child2->setId('id2');
+
+    $root->addChild($child1);
+    $root->addChild($child2);
+
+    $root->checkChildrenIds();
+  }
+
+  function testDuplicateIdsError()
+  {
+    $root = new lmbMacroNode;
+    $child1 = new lmbMacroNode(new lmbMacroSourceLocation('my_file', 10));
+    $child1->setId('my_tag');
+    $root->addChild($child1);
+
+    $child2 = new lmbMacroNode(new lmbMacroSourceLocation('my_file2', 15));
+    $child2->setId('my_tag');
+    $root->addChild($child2);
+
+    try
+    {
+      $root->checkChildrenIds();
+      $this->assertTrue(false);
+    }
+    catch(lmbMacroException $e)
+    {
+      $this->assertWantedPattern('/Duplicate "id" attribute/', $e->getMessage());
+      $params = $e->getParams();
+      $this->assertEqual($params['file'], 'my_file2');
+      $this->assertEqual($params['line'], 15);
+      $this->assertEqual($params['duplicate_node_file'], 'my_file');
+      $this->assertEqual($params['duplicate_node_line'], 10);
+    }
+  }
+
+  function testDuplicateIdIsLegalInDifferentBranches()
+  {
+    $root = new lmbMacroNode;
+
+    $Branch = new lmbMacroNode;
+    $root->addChild($Branch);
+
+    $child1 = new lmbMacroNode;
+    $child1->setId('my_tag');
+    $Branch->addChild($child1);
+
+    $child2 = new MockMacroNode();
+    $child2->setId('my_tag');
+    $root->addChild($child2);
+
+    $root->checkChildrenIds();
+  }  
+  
+  function testGetIdByDefault()
+  {
+    $this->assertNotNull($this->node->getId());
+  }  
+
+  function testGetId()
+  {
+    $this->node->setId('TestId');
+    $this->assertEqual($this->node->getId(), 'TestId');
+  }
+  
+  function testGetAttributeUnset()
+  {
+    $this->assertNull($this->node->get('foo'));
+  }  
+
+  function testGetAttribute()
+  {
+    $this->node->set('foo', 'bar');
+    $this->assertEqual($this->node->get('foo'), 'bar');
+    $this->assertEqual($this->node->get('FOO'), 'bar');
+  }
+
+  function testHasAttribute()
+  {
+    $this->node->set('foo', 'bar');
+    $this->node->set('tricky', NULL);
+    $this->assertTrue($this->node->has('foo'));
+    $this->assertTrue($this->node->has('tricky'));
+    $this->assertFalse($this->node->has('missing'));
+    $this->assertTrue($this->node->has('FOO'));
+    $this->assertTrue($this->node->has('TRICKY'));
+    $this->assertFalse($this->node->has('MISSING'));
+  }
+
+  function testRemoveAttribute()
+  {
+    $this->node->set('foo', 'bar');
+    $this->node->set('untouched', 'value');
+    $this->assertTrue($this->node->has('foo'));
+    $this->node->remove('FOO');
+    $this->assertFalse($this->node->has('foo'));
+  }
+
+  function testBooleanAttribute()
+  {
+    //true cases
+    $this->node->set('B', 'True');
+    $this->assertTrue($this->node->getBool('B'));
+
+    $this->node->set('C', 'Something');
+    $this->assertTrue($this->node->getBool('C'));
+
+    //false cases
+    $this->node->set('A', NULL);
+    $this->assertFalse($this->node->getBool('A'));
+    
+    $this->node->set('D', 'False');
+    $this->assertFalse($this->node->getBool('D'));
+
+    $this->assertFalse($this->node->getBool('E'));
+
+    $this->node->set('F', 'n');
+    $this->assertFalse($this->node->getBool('F'));
+
+    $this->node->set('G', 'No');
+    $this->assertFalse($this->node->getBool('G'));
+
+    $this->node->set('H', 'none');
+    $this->assertFalse($this->node->getBool('H'));
+
+    $this->node->set('I', '0');
+    $this->assertFalse($this->node->getBool('I'));
+  }
+
+  function testPreparseAndCheckForRequiredAttributes()
+  {
+    $this->tag_info->setRequiredAttributes(array('bar'));
+    $this->node->set('bar', null);
+    $this->node->preParse();
+  }
+
+  function testPreparseAndCheckForMissedRequiredAttributes()
+  {
+    $this->tag_info->setRequiredAttributes(array('bar'));
+
+    try
+    {
+      $this->node->preParse();
+      $this->assertTrue(false);
+    }
+    catch(lmbMacroException $e)
+    {
+      $this->assertWantedPattern('/Missing required attribute/', $e->getMessage());
+      $this->assertEqual($e->getParam('attribute'), 'bar');
+    }
+  }
+
+  function testRestrictSelfNesting()
+  {
+    $tag_info = new lmbMacroTagInfo('CompilerTag', 'whatever');
+    $tag_info->setRestrictSelfNesting(true);
+
+    $node = new lmbMacroTag(new lmbMacroSourceLocation('my_file', 13), 'whatever', $tag_info);
+
+    $parent = new lmbMacroTag(new lmbMacroSourceLocation('my_file', 10), 'whatEver', $tag_info);
+    $node->setParent($parent);
+
+    try
+    {
+      $node->preParse();
+      $this->assertTrue(false);
+    }
+    catch(lmbMacroException $e)
+    {
+      $this->assertWantedPattern('/Tag cannot be nested within the same tag/', $e->getMessage());
+      $this->assertEqual($e->getParam('same_tag_file'), 'my_file');
+      $this->assertEqual($e->getParam('same_tag_line'), 10);
+    }
+  }
+
+  function testCheckParentTagClassOk()
+  {
+    $this->tag_info->setParentClass('MacroTagClass1CompilerTest');
+
+    $parent = new MacroTagClass1CompilerTest(null, null, null);
+    $this->node->setParent($parent);
+
+    $this->node->preParse();
+  }
+
+  function testCheckParentTagClassException()
+  {
+    $this->tag_info->setParentClass('MacroTagClass1CompilerTest');
+
+    $parent = new MacroTagClass2CompilerTest(null, null, null);
+    $this->node->setParent($parent);
+
+    try
+    {
+      $this->node->preParse();
+      $this->assertTrue(false);
+    }
+    catch(lmbMacroException $e)
+    {
+      $this->assertWantedPattern('/Tag must be enclosed by a proper parent tag/', $e->getMessage());
+      $this->assertEqual($e->getParam('required_parent_tag_class'), 'MacroTagClass1CompilerTest');
+      $this->assertEqual($e->getParam('file'), $this->source_location->getFile());
+      $this->assertEqual($e->getParam('line'), $this->source_location->getLine());
+    }
+  }  
+}
+?>
\ No newline at end of file



More information about the limb-svn mailing list