diff --git a/lib/tests/portfoliolib_test.php b/lib/tests/portfoliolib_test.php
new file mode 100644
index 00000000000..1d8a0517a64
--- /dev/null
+++ b/lib/tests/portfoliolib_test.php
@@ -0,0 +1,170 @@
+.
+
+/**
+ * Portfolio lib tests.
+ *
+ * @package core
+ * @subpackage phpunit
+ * @copyright 2014 Frédéric Massart
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+global $CFG;
+
+require_once($CFG->libdir.'/portfoliolib.php');
+require_once($CFG->libdir.'/portfolio/formats.php');
+
+/**
+ * Portfolio lib testcase.
+ *
+ * @copyright 2014 Frédéric Massart
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_portfoliolib_testcase extends advanced_testcase {
+
+ public function test_portfolio_rewrite_pluginfile_urls() {
+ $this->resetAfterTest();
+
+ // File info.
+ $context = context_system::instance();
+ $component = 'core_test';
+ $filearea = 'fixture';
+ $filepath = '/';
+ $itemid = 0;
+ $filenameimg = 'file.png';
+ $filenamepdf = 'file.pdf';
+
+ // Store 2 test files in the pool.
+ $fs = get_file_storage();
+ $filerecord = array(
+ 'contextid' => $context->id,
+ 'component' => $component,
+ 'filearea' => $filearea,
+ 'itemid' => $itemid,
+ 'filepath' => $filepath,
+ 'filename' => $filenameimg,
+ );
+ $fileimg = $fs->create_file_from_string($filerecord, 'test');
+
+ $filerecord['filename'] = $filenamepdf;
+ $filepdf = $fs->create_file_from_string($filerecord, 'test');
+
+ // Test that nothing is matching.
+ $format = '';
+ $options = null;
+ $input = '
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($input, $output);
+
+ $input = 'Here, the

@@PLUGINFILE@@' . $filepath . $filenameimg .
+ ' is not supposed to be an actual URL placeholder.
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($input, $output);
+
+ // Now use our dummy format.
+ $format = new core_portfolio_format_dummytest();
+ $options = null;
+
+ // Test that the link is matching.
+ $input = 'Come and join us!?
';
+ $expected = 'Come and ' . $filenamepdf . '?
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ $input = 'Come and join us!?
';
+ $expected = 'Come and ' . $filenamepdf . '?
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ // Test that the image is matching.
+ $input = 'Here is an image 
'; // No trailing slash.
+ $expected = 'Here is an image 
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ $input = 'Here is an image 
'; // Trailing slash.
+ $expected = 'Here is an image 
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ // Test that the attributes are kept.
+ $input = 'join us!
';
+ $expected = '' . $filenamepdf . '
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ $input = '
';
+ $expected = '
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ // Test with more tags around.
+ $input = '' .
+ 'join us!
';
+ $expected = '' . $filenamepdf . '
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ $input = '
';
+ $expected = '
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ // Test multiple on same line.
+ $input = 'join us!' .
+ 'join us!
';
+ $expected = '' . $filenamepdf . '' .
+ '' . $filenamepdf . '
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ $input = '
' .
+ '
';
+ $expected = '

';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+
+ $input = 'join us!' .
+ '
';
+ $expected = '' . $filenamepdf . '' .
+ '
';
+ $output = portfolio_rewrite_pluginfile_urls($input, $context->id, $component, $filearea, $itemid, $format, $options);
+ $this->assertSame($expected, $output);
+ }
+}
+
+/**
+ * Dummy portfolio format.
+ *
+ * @copyright 2014 Frédéric Massart
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_portfolio_format_dummytest extends portfolio_format {
+
+ public static function file_output($file, $options = null) {
+ if (isset($options['attributes']) && is_array($options['attributes'])) {
+ $attributes = $options['attributes'];
+ } else {
+ $attributes = array();
+ }
+ $path = 'files/' . $file->get_filename();
+ return self::make_tag($file, $path, $attributes);
+ }
+
+}