From f33829da897488b098c24ba10d935fa1dbb547a5 Mon Sep 17 00:00:00 2001
From: benakamoorthi <benaka.moorthi@gmail.com>
Date: Tue, 18 Dec 2012 02:53:55 +0000
Subject: [PATCH] Refs #1253, fixes #3349, fix bugs and regressions in
 annotations and tweaked the UI a bit.

git-svn-id: http://dev.piwik.org/svn/trunk@7648 59fd770c-687e-43c8-a1e3-f5a4ff64c105
---
 core/DataTable.php                            | 13 ++++
 core/DataTable/Renderer.php                   | 10 ++-
 core/DataTable/Renderer/Console.php           |  5 ++
 core/DataTable/Renderer/Csv.php               |  9 ++-
 core/DataTable/Renderer/Html.php              |  5 ++
 core/DataTable/Renderer/Json.php              |  2 +-
 core/DataTable/Renderer/Xml.php               |  3 +-
 lang/en.php                                   | 10 +--
 plugins/Annotations/API.php                   | 66 ++++++++--------
 plugins/Annotations/AnnotationList.php        | 14 ++--
 plugins/Annotations/templates/annotation.tpl  |  2 +-
 .../templates/annotationManager.tpl           |  2 +-
 plugins/Annotations/templates/annotations.js  | 19 ++++-
 plugins/CoreHome/templates/datatable.js       | 10 ++-
 .../Core/DataTable/Renderer/CSVTest.php       | 75 +++++++++++++++++++
 .../Core/DataTable/Renderer/ConsoleTest.php   | 74 ++++++++++++++++++
 .../Core/DataTable/Renderer/JSONTest.php      | 23 +++++-
 .../Core/DataTable/Renderer/XMLTest.php       | 14 +++-
 18 files changed, 291 insertions(+), 65 deletions(-)

diff --git a/core/DataTable.php b/core/DataTable.php
index 82933d58ca..df325fb5e9 100644
--- a/core/DataTable.php
+++ b/core/DataTable.php
@@ -1490,4 +1490,17 @@ class Piwik_DataTable
 		}
 		return $result;
 	}
+	
+	/**
+	 * Returns a new DataTable created with data from a 'simple' array.
+	 * 
+	 * @param array $array
+	 * @return Piwik_DataTable
+	 */
+	public static function makeFromSimpleArray( $array )
+	{
+		$dataTable = new Piwik_DataTable();
+		$dataTable->addRowsFromSimpleArray($array);
+		return $dataTable;
+	}
 }
diff --git a/core/DataTable/Renderer.php b/core/DataTable/Renderer.php
index 8f48e88903..3196b67740 100644
--- a/core/DataTable/Renderer.php
+++ b/core/DataTable/Renderer.php
@@ -365,7 +365,7 @@ abstract class Piwik_DataTable_Renderer
 	 * In the old code, arrays were added to new DataTable instances, and then rendered.
 	 * This transformation wrapped associative arrays except under certain circumstances,
 	 * including:
-	 *  - single element (ie, array('nb_visits' => 0))
+	 *  - single element (ie, array('nb_visits' => 0))   (not wrapped for some renderers)
 	 *  - empty array (ie, array())
 	 *  - array w/ arrays/DataTable instances as values (ie,
 	 *			array('name' => 'myreport',
@@ -374,11 +374,14 @@ abstract class Piwik_DataTable_Renderer
 	 *				  'reportData' => array(...)) )
 	 * 
 	 * @param array $array
+	 * @param bool $wrapSingleValues Whether to wrap array('key' => 'value') arrays. Some
+	 *                               renderers wrap them and some don't.
 	 * @param bool|null $isAssociativeArray Whether the array is associative or not.
 	 *                                      If null, it is determined.
 	 * @return bool
 	 */
-	protected static function shouldWrapArrayBeforeRendering( $array, $isAssociativeArray = null )
+	protected static function shouldWrapArrayBeforeRendering(
+		$array, $wrapSingleValues = true, $isAssociativeArray = null )
 	{
 		if (empty($array))
 		{
@@ -395,7 +398,8 @@ abstract class Piwik_DataTable_Renderer
 		{
 			// we don't wrap if the array has one element that is a value
 			$firstValue = reset($array);
-			if (count($array) === 1
+			if (!$wrapSingleValues
+				&& count($array) === 1
 				&& (!is_array($firstValue)
 					&& !is_object($firstValue)))
 			{
diff --git a/core/DataTable/Renderer/Console.php b/core/DataTable/Renderer/Console.php
index 78266bb67c..aeae7d058b 100644
--- a/core/DataTable/Renderer/Console.php
+++ b/core/DataTable/Renderer/Console.php
@@ -98,6 +98,11 @@ class Piwik_DataTable_Renderer_Console extends Piwik_DataTable_Renderer
 	 */
 	protected function renderTable($table, $prefix = "")
 	{
+		if (is_array($table)) // convert array to DataTable
+		{
+			$table = Piwik_DataTable::makeFromSimpleArray($table);
+		}
+		
 		if($table instanceof Piwik_DataTable_Array)
 		{
 			return $this->renderDataTableArray($table, $prefix);
diff --git a/core/DataTable/Renderer/Csv.php b/core/DataTable/Renderer/Csv.php
index 48f2c81005..bddbb3b884 100644
--- a/core/DataTable/Renderer/Csv.php
+++ b/core/DataTable/Renderer/Csv.php
@@ -117,12 +117,17 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
 	/**
 	 * Computes the output of the given data table
 	 *
-	 * @param Piwik_DataTable  $table
-	 * @param array            $allColumns
+	 * @param Piwik_DataTable|array  $table
+	 * @param array            		 $allColumns
 	 * @return string
 	 */
 	protected function renderTable($table, &$allColumns = array() )
 	{
+		if (is_array($table)) // convert array to DataTable
+		{
+			$table = Piwik_DataTable::makeFromSimpleArray($table);
+		}
+		
 		if($table instanceof Piwik_DataTable_Array)
 		{
 			$str = $this->renderDataTableArray($table, $allColumns);
diff --git a/core/DataTable/Renderer/Html.php b/core/DataTable/Renderer/Html.php
index c9ec98f3e5..5e913e22be 100644
--- a/core/DataTable/Renderer/Html.php
+++ b/core/DataTable/Renderer/Html.php
@@ -77,6 +77,11 @@ class Piwik_DataTable_Renderer_Html extends Piwik_DataTable_Renderer
 	 */
 	protected function renderTable($table)
 	{
+		if (is_array($table)) // convert array to DataTable
+		{
+			$table = Piwik_DataTable::makeFromSimpleArray($table);
+		}
+		
 		if($table instanceof Piwik_DataTable_Array)
 		{
 			foreach($table->getArray() as $date => $subtable )
diff --git a/core/DataTable/Renderer/Json.php b/core/DataTable/Renderer/Json.php
index 812eb4e76a..f026663e50 100644
--- a/core/DataTable/Renderer/Json.php
+++ b/core/DataTable/Renderer/Json.php
@@ -57,7 +57,7 @@ class Piwik_DataTable_Renderer_Json extends Piwik_DataTable_Renderer
 		if (is_array($table))
 		{
 			$array = $table;
-			if (self::shouldWrapArrayBeforeRendering($array))
+			if (self::shouldWrapArrayBeforeRendering($array, $wrapSingleValues = true))
 			{
 				$array = array($array);
 			}
diff --git a/core/DataTable/Renderer/Xml.php b/core/DataTable/Renderer/Xml.php
index ea3c546f6d..b2261940d5 100644
--- a/core/DataTable/Renderer/Xml.php
+++ b/core/DataTable/Renderer/Xml.php
@@ -180,7 +180,8 @@ class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer
 		// NOTE: this is for backwards compatibility. before, array's were added to a new DataTable.
 		// if the array had arrays, they were added as multiple rows, otherwise it was treated as
 		// one row. removing will change API output.
-		$wrapInRow = $prefixLines === "\t" && self::shouldWrapArrayBeforeRendering($array, $isAssociativeArray);
+		$wrapInRow = $prefixLines === "\t"
+				  && self::shouldWrapArrayBeforeRendering($array, $wrapSingleValues = false, $isAssociativeArray);
 		
 		// render the array
 		$result = "";
diff --git a/lang/en.php b/lang/en.php
index 06e1a47225..75ec585c86 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -1878,20 +1878,20 @@ And thank you for using Piwik!',
 	'Overlay_ErrorNotLoadingDetails' => 'Maybe the page loaded on the right doesn\'t have the Piwik tracker code. In this case, try launching Overlay for a different page from the pages report.',
 	'Overlay_ErrorNotLoadingDetailsSSL' => 'Since you\'re using Piwik over https, the most likely cause is that your website doesn\'t support SSL. Try using Piwik over http.',
 	'Overlay_ErrorNotLoadingLink' => 'Click here to get more tips for troubleshooting',
-	'Annotations_PluginDescription' => 'Allows you to attach notes to different days so you will be remember why your data looks the way it does.',
+	'Annotations_PluginDescription' => 'Allows you to attach notes to different days to mark changes made to your website, save analyses you make regarding your data and share your thoughts with your colleagues. By annotating your data, you will make sure you remember why your data looks the way it does.',
 	'Annotations_Annotations' => 'Annotations',
 	'Annotations_EnterAnnotationText' => 'Enter your note...',
 	'CoreHome_Annotations_IconDesc_js' => 'View notes for this date range.',
 	'CoreHome_Annotations_IconDescHideNotes_js' => 'Hide notes for this date range.',
-	'Annotations_NoAnnotations' => 'There are no notes for this date range.',
+	'Annotations_NoAnnotations' => 'There are no annotations for this date range.',
+	'Annotations_InlineQuickHelp' => 'You can create annotations to mark special events (like a new blog post, or website redesign), to save your data analyses or to save anything else you think is important.',
 	'CoreHome_Annotations_ViewAndAddAnnotations_js' => 'View and add annotations for %s...',
 	'CoreHome_Annotations_HideAnnotationsFor_js' => 'Hide annotations for %s...',
 	'CoreHome_Annotations_AddAnnotationsFor_js' => 'Add annotations for %s...',
-	'Annotations_ClickToAdd' => 'Click to add an annotation.',
 	'Annotations_ClickToEdit' => 'Click to edit this annotation.',
 	'Annotations_ClickToDelete' => 'Click to delete this annotation.',
 	'Annotations_ClickToStarOrUnstar' => 'Click to star or unstar this annotation.',
-	'Annotations_YouCannotModifyThisNote' => 'You cannot modify this note, because you did not create it, nor do you do not have admin access for this site.',
-	'Annotations_CreateNewAnnotation' => 'Create new annotation...',
+	'Annotations_YouCannotModifyThisNote' => 'You cannot modify this annotation, because you did not create it, nor do you have admin access for this site.',
+	'Annotations_CreateNewAnnotation' => 'Create a new annotation...',
 	'Annotations_LoginToAnnotate' => 'Login to create an annotation.',
 );
diff --git a/plugins/Annotations/API.php b/plugins/Annotations/API.php
index cc49d59492..1ce6a469e3 100755
--- a/plugins/Annotations/API.php
+++ b/plugins/Annotations/API.php
@@ -52,16 +52,8 @@ class Piwik_Annotations_API
 	 */
 	public function add( $idSite, $date, $note, $starred = 0 )
 	{
-		// can only add a note to one site
-		if (!is_numeric($idSite))
-		{
-			throw new Exception("Invalid idSite: '$idSite'. Note: Cannot add one note to multiple sites.");
-		}
-		
-		// make sure date is a valid date
-		Piwik_Date::factory($date);
-		
-		// check permissions
+		$this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot add one note to multiple sites.");
+		$this->checkDateIsValid($date);
 		$this->checkUserCanAddNotesFor($idSite);
 		
 		// add, save & return a new annotation
@@ -97,17 +89,8 @@ class Piwik_Annotations_API
 	 */
 	public function save( $idSite, $idNote, $date = null, $note = null, $starred = null )
 	{
-		// cannot update notes for multiple sites
-		if (!is_numeric($idSite))
-		{
-			throw new Exception("Invalid idSite: '$idSite'. Note: Cannot modify more than one note at a time.");
-		}
-		
-		// make sure date is a valid date
-		if ($date !== null)
-		{
-			Piwik_Date::factory($date);
-		}
+		$this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot modify more than one note at a time.");
+		$this->checkDateIsValid($date, $canBeNull = true);
 		
 		// get the annotations for the site
 		$annotations = new Piwik_Annotations_AnnotationList($idSite);
@@ -136,11 +119,7 @@ class Piwik_Annotations_API
 	 */
 	public function delete( $idSite, $idNote )
 	{
-		// check that $idSite is single
-		if (!is_numeric($idSite))
-		{
-			throw new Exception("Invalid idSite: '$idSite'. Note: Cannot delete multiple notes.");
-		}
+		$this->checkSingleIdSite($idSite, $extraMessage = "Note: Cannot delete multiple notes.");
 		
 		$annotations = new Piwik_Annotations_AnnotationList($idSite);
 		
@@ -167,12 +146,7 @@ class Piwik_Annotations_API
 	 */
 	public function get( $idSite, $idNote )
 	{
-		// getting a single note means only ONE idSite
-		if (!is_numeric($idSite))
-		{
-			throw new Exception("Invalid idSite: '$idSite'. Note: Specify only one site ID when getting ONE note.");
-		}
-		
+		$this->checkSingleIdSite($idSite, $extraMessage = "Note: Specify only one site ID when getting ONE note.");
 		Piwik::checkUserHasViewAccess($idSite);
 		
 		// get single annotation
@@ -361,4 +335,32 @@ class Piwik_Annotations_API
 		}
 		return array($startDate, $endDate);
 	}
+	
+	/**
+	 * Utility function, makes sure idSite string has only one site ID and throws if
+	 * otherwise.
+	 */
+	private function checkSingleIdSite( $idSite, $extraMessage )
+	{
+		// can only add a note to one site
+		if (!is_numeric($idSite))
+		{
+			throw new Exception("Invalid idSite: '$idSite'. $extraMessage");
+		}
+	}
+	
+	/**
+	 * Utility function, makes sure date string is valid date, and throws if
+	 * otherwise.
+	 */
+	private function checkDateIsValid( $date, $canBeNull = false )
+	{
+		if ($date === null
+			&& $canBeNull)
+		{
+			return;
+		}
+		
+		Piwik_Date::factory($date);
+	}
 }
diff --git a/plugins/Annotations/AnnotationList.php b/plugins/Annotations/AnnotationList.php
index 8031d5c468..f335c1315b 100755
--- a/plugins/Annotations/AnnotationList.php
+++ b/plugins/Annotations/AnnotationList.php
@@ -267,18 +267,16 @@ class Piwik_Annotations_AnnotationList
 	{
 		$this->checkIdSiteIsLoaded($idSite);
 		
+		// search includes end date, and count should not, so subtract one from the timestamp
+		$annotations = $this->search($startDate, Piwik_Date::factory($endDate->getTimestamp() - 1));
+		
 		// count the annotations
 		$count = $starred = 0;
-		foreach ($this->annotations[$idSite] as $annotation)
+		if (!empty($annotations[$idSite]))
 		{
-			$annotationDate = Piwik_Date::factory($annotation['date']);
-			
-			// if annotation start date is between start date & end date, increment count
-			if ($annotationDate->getTimestamp() >= $startDate->getTimestamp()
-				&& $annotationDate->getTimestamp() < $endDate->getTimestamp())
+			$count = count($annotations[$idSite]);
+			foreach ($annotations[$idSite] as $annotation)
 			{
-				++$count;
-				
 				if ($annotation['starred'])
 				{
 					++$starred;
diff --git a/plugins/Annotations/templates/annotation.tpl b/plugins/Annotations/templates/annotation.tpl
index 1a94cf60d6..e1cd5f6013 100755
--- a/plugins/Annotations/templates/annotation.tpl
+++ b/plugins/Annotations/templates/annotation.tpl
@@ -35,7 +35,7 @@
 	<td class="annotation-user-cell">
 		<span class="annotation-user">{$annotation.user|unescape|escape:'html'}</span><br/>
 		{if $annotation.canEditOrDelete}
-		<a href="#" class="delete-annotation" style="display:none" title="{'Annotations_ClickToDelete'|translate}">Delete</a>
+		<a href="#" class="delete-annotation" style="display:none" title="{'Annotations_ClickToDelete'|translate}">{'General_Delete'|translate}</a>
 		{/if}
 	</td>
 	{/if}
diff --git a/plugins/Annotations/templates/annotationManager.tpl b/plugins/Annotations/templates/annotationManager.tpl
index 4afa631cfd..7ba893a972 100755
--- a/plugins/Annotations/templates/annotationManager.tpl
+++ b/plugins/Annotations/templates/annotationManager.tpl
@@ -18,7 +18,7 @@
 
 <div class="annotation-controls">
 	{if $canUserAddNotes}
-	<a href="#" class="add-annotation" title="{'Annotations_ClickToAdd'|translate}">{'Annotations_CreateNewAnnotation'|translate}</a>
+	<a href="#" class="add-annotation">{'Annotations_CreateNewAnnotation'|translate}</a>
 	{elseif $userLogin eq 'anonymous'}
 	<a href="index.php?module=Login">{'Annotations_LoginToAnnotate'|translate}</a>
 	{/if}
diff --git a/plugins/Annotations/templates/annotations.js b/plugins/Annotations/templates/annotations.js
index 0a7ed20edd..925c652567 100755
--- a/plugins/Annotations/templates/annotations.js
+++ b/plugins/Annotations/templates/annotations.js
@@ -159,6 +159,7 @@ var getDatePickerOptions = function(annotation)
 	result.onSelect = function (dateText)
 	{
 		$('.annotation-period-edit>a', annotation).text(dateText);
+		$('.datepicker', annotation).hide();
 	};
 	
 	return result;
@@ -293,6 +294,7 @@ var bindAnnotationManagerEvents = function(manager, idSite, onAnnotationCountCha
 		
 		// disable input & link
 		addNoteInput.attr('disabled', 'disabled');
+		$(this).attr('disabled', 'disabled');
 		
 		// add a new annotation for the site, date & period
 		annotationsApi.addAnnotation(
@@ -349,6 +351,7 @@ var bindAnnotationManagerEvents = function(manager, idSite, onAnnotationCountCha
 		
 		// disable input while ajax is happening
 		input.attr('disabled', 'disabled');
+		$(this).attr('disabled', 'disabled');
 	
 		// save the note w/ the new note text & date
 		annotationsApi.saveAnnotation(
@@ -402,8 +405,8 @@ var bindAnnotationManagerEvents = function(manager, idSite, onAnnotationCountCha
 			manager.attr('data-date'),
 			manager.attr('data-period'),
 			function (response) {
-				manager.html($(response).html());
-			
+				replaceAnnotationManager(manager, response);
+				
 				// update evolution icons
 				var isStarred = isAnnotationStarred(annotation);
 				onAnnotationCountChange(annotation.attr('data-date'), -1, isStarred ? -1 : 0);
@@ -455,6 +458,9 @@ var bindAnnotationManagerEvents = function(manager, idSite, onAnnotationCountCha
 	});
 };
 
+// used in below function
+var loadingAnnotationManager = false;
+
 /**
  * Shows an annotation manager under a report for a specific site & date range.
  * 
@@ -543,6 +549,14 @@ var showAnnotationViewer = function(domElem, idSite, date, period, lastN, callba
 	}
 	else
 	{
+		// if we are already loading the annotation manager, don't load it again
+		if (loadingAnnotationManager)
+		{
+			return;
+		}
+		
+		loadingAnnotationManager = true;
+		
 		var loading = $('.loadingPiwikBelow', domElem).css({display: 'block'});
 		
 		// the annotations for this report have not been retrieved yet, so do an ajax request
@@ -567,6 +581,7 @@ var showAnnotationViewer = function(domElem, idSite, date, period, lastN, callba
 			$('.dataTableFeatures', domElem).append(manager);
 			manager.slideDown('slow', function() {
 				loading.hide().css('visibility', 'visible');
+				loadingAnnotationManager = false;
 			
 				if (callback) callback(manager)
 			});
diff --git a/plugins/CoreHome/templates/datatable.js b/plugins/CoreHome/templates/datatable.js
index a2e57f098a..7b56b7e744 100644
--- a/plugins/CoreHome/templates/datatable.js
+++ b/plugins/CoreHome/templates/datatable.js
@@ -590,18 +590,24 @@ dataTable.prototype =
 						}
 					);
 				
-					// when clicking an annotation, show the annotation viewer for that day
+					// when clicking an annotation, show the annotation viewer for that period
 					$('span', annotations).click(function() {
 						var spanSelf = $(this),
 							date = spanSelf.attr('data-date'),
 							oldDate = $('.annotation-manager', domElem).attr('data-date');
 						if (date)
 						{
+							var period = self.param.period;
+							if (period == 'range')
+							{
+								period = 'day';
+							}
+							
 							piwik.annotations.showAnnotationViewer(
 								domElem,
 								self.param.idSite,
 								date,
-								self.param.period,
+								period,
 								undefined, // lastN
 								function (manager) {
 									manager.attr('data-is-range', 0);
diff --git a/tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php b/tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php
index 3e4a62829d..a93886f8a0 100644
--- a/tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php
+++ b/tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php
@@ -412,4 +412,79 @@ class DataTable_Renderer_CSVTest extends PHPUnit_Framework_TestCase
         $rendered = $render->render();
         $this->assertEquals($expected, $rendered);
     }
+    
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_XML
+	 */
+	public function testRenderArray1()
+	{
+		$data = array();
+		
+        $render = new Piwik_DataTable_Renderer_Csv();
+        $render->setTable($data);
+        $render->convertToUnicode = false;
+        $expected = 'No data available';
+        
+        $this->assertEquals($expected, $render->render());
+	}
+    
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_XML
+	 */
+	public function testRenderArray2()
+	{
+		$data = array('a', 'b', 'c');
+		
+        $render = new Piwik_DataTable_Renderer_Csv();
+        $render->setTable($data);
+        $render->convertToUnicode = false;
+        $expected = 'a
+b
+c';
+        
+        $this->assertEquals($expected, $render->render());
+	}
+    
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_XML
+	 */
+	public function testRenderArray3()
+	{
+		$data = array('a' => 'b', 'c' => 'd', 'e' => 'f', 5 => 'g');
+		
+        $render = new Piwik_DataTable_Renderer_Csv();
+        $render->setTable($data);
+        $render->convertToUnicode = false;
+        $expected = 'a,c,e,5
+b,d,f,g';
+        
+        $this->assertEquals($expected, $render->render());
+	}
+	
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_XML
+	 */
+	public function testRenderArray4()
+	{
+		$data = array('a' => 'b');
+		
+        $render = new Piwik_DataTable_Renderer_Csv();
+        $render->setTable($data);
+        $render->convertToUnicode = false;
+        $expected = 'b';
+        
+        $this->assertEquals($expected, $render->render());
+	}
 }
diff --git a/tests/PHPUnit/Core/DataTable/Renderer/ConsoleTest.php b/tests/PHPUnit/Core/DataTable/Renderer/ConsoleTest.php
index 9f139c719d..bea84a0ea6 100644
--- a/tests/PHPUnit/Core/DataTable/Renderer/ConsoleTest.php
+++ b/tests/PHPUnit/Core/DataTable/Renderer/ConsoleTest.php
@@ -88,4 +88,78 @@ class DataTable_Renderer_ConsoleTest extends PHPUnit_Framework_TestCase
 
         $this->assertEquals($expected, $rendered);
     }
+
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_XML
+	 */
+	public function testRenderArray1()
+	{
+		$data = array();
+		
+        $render = new Piwik_DataTable_Renderer_Console();
+        $render->setTable($data);
+        $expected = 'Empty table<br />
+';
+        
+        $this->assertEquals($expected, $render->render());
+	}
+    
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_XML
+	 */
+	public function testRenderArray2()
+	{
+		$data = array('a', 'b', 'c');
+		
+        $render = new Piwik_DataTable_Renderer_Console();
+        $render->setTable($data);
+        $expected = "- 1 ['0' => 'a'] [] [idsubtable = ]<br />
+- 2 ['0' => 'b'] [] [idsubtable = ]<br />
+- 3 ['0' => 'c'] [] [idsubtable = ]<br />
+";
+        
+        $this->assertEquals($expected, $render->render());
+	}
+    
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_XML
+	 */
+	public function testRenderArray3()
+	{
+		$data = array('a' => 'b', 'c' => 'd', 'e' => 'f', 5 => 'g');
+		
+        $render = new Piwik_DataTable_Renderer_Console();
+        $render->setTable($data);
+        $expected = "- 1 ['a' => 'b', 'c' => 'd', 'e' => 'f', '5' => 'g'] [] [idsubtable = ]<br />
+";
+        
+        $this->assertEquals($expected, $render->render());
+	}
+	
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_XML
+	 */
+	public function testRenderArray4()
+	{
+		$data = array('a' => 'b');
+		
+        $render = new Piwik_DataTable_Renderer_Console();
+        $render->setTable($data);
+        $expected = "- 1 ['0' => 'b'] [] [idsubtable = ]<br />
+";
+        
+        $this->assertEquals($expected, $render->render());
+	}
 }
diff --git a/tests/PHPUnit/Core/DataTable/Renderer/JSONTest.php b/tests/PHPUnit/Core/DataTable/Renderer/JSONTest.php
index c5970b3997..2c3bf653fd 100644
--- a/tests/PHPUnit/Core/DataTable/Renderer/JSONTest.php
+++ b/tests/PHPUnit/Core/DataTable/Renderer/JSONTest.php
@@ -412,7 +412,7 @@ class DataTable_Renderer_JSONTest extends PHPUnit_Framework_TestCase
 	 * @group Core
 	 * @group DataTable
 	 * @group DataTable_Renderer
-	 * @group DataTable_Renderer_XML
+	 * @group DataTable_Renderer_JSON
 	 */
 	public function testRenderArray2()
 	{
@@ -429,7 +429,7 @@ class DataTable_Renderer_JSONTest extends PHPUnit_Framework_TestCase
 	 * @group Core
 	 * @group DataTable
 	 * @group DataTable_Renderer
-	 * @group DataTable_Renderer_XML
+	 * @group DataTable_Renderer_JSON
 	 */
 	public function testRenderArray3()
 	{
@@ -446,7 +446,7 @@ class DataTable_Renderer_JSONTest extends PHPUnit_Framework_TestCase
 	 * @group Core
 	 * @group DataTable
 	 * @group DataTable_Renderer
-	 * @group DataTable_Renderer_XML
+	 * @group DataTable_Renderer_JSON
 	 */
 	public function testRenderArray4()
 	{
@@ -458,5 +458,22 @@ class DataTable_Renderer_JSONTest extends PHPUnit_Framework_TestCase
         
         $this->assertEquals($expected, $render->render());
 	}
+	
+	/**
+	 * @group Core
+	 * @group DataTable
+	 * @group DataTable_Renderer
+	 * @group DataTable_Renderer_JSON
+	 */
+	public function testRenderArray5()
+	{
+		$data = array('a' => 'b');
+		
+        $render = new Piwik_DataTable_Renderer_Json();
+		$render->setTable($data);
+		$expected = '[{"a":"b"}]';
+        
+        $this->assertEquals($expected, $render->render());
+	}
 
 }
diff --git a/tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php b/tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php
index 0594c0a1da..7291222390 100644
--- a/tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php
+++ b/tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php
@@ -574,15 +574,21 @@ class DataTable_Renderer_XMLTest extends PHPUnit_Framework_TestCase
 	 */
 	public function testRenderArray2()
 	{
-		$data = array('a', 'b', 'c');
+		$data = array("firstElement", 
+					  array("firstElement", 
+							"secondElement"), 
+					  "thirdElement");
 		
         $render = new Piwik_DataTable_Renderer_Xml();
         $render->setTable($data);
         $expected = '<?xml version="1.0" encoding="utf-8" ?>
 <result>
-	<row>a</row>
-	<row>b</row>
-	<row>c</row>
+	<row>firstElement</row>
+	<row>
+		<row>firstElement</row>
+		<row>secondElement</row>
+	</row>
+	<row>thirdElement</row>
 </result>';
         
         $this->assertEquals($expected, $render->render());
-- 
GitLab