Browse Source

add tests with copilot

master
Martin Monperrus 6 months ago
parent
commit
4cdfb81a64
No known key found for this signature in database GPG Key ID: 7D398AD45AEEEC93
  1. 388
      BibtexbrowserTest.php
  2. 61
      bibtexbrowser.php

388
BibtexbrowserTest.php

@ -7,6 +7,7 @@ $ phpunit BibtexbrowserTest.php
With coverage:
$ phpunit --coverage-html ./coverage BibtexbrowserTest.php
$ XDEBUG_MODE=coverage phpunit --coverage-filter bibtexbrowser.php --coverage-html=foo.html BibtexbrowserTest.php
(be sure that xdebug is enabled: /etc/php5/cli/conf.d# ln -s ../../mods-available/xdebug.ini)
*/
@ -748,6 +749,7 @@ class BibtexbrowserTest extends PHPUnit_Framework_TestCase {
fseek($test_data,0);
$db = new BibDataBase();
$db->update_internal("inline", $test_data);
$entry=$db->getEntryByKey($key);
$this->assertEquals($bibtex, $entry->getText());
}
@ -984,10 +986,396 @@ class BibtexbrowserTest extends PHPUnit_Framework_TestCase {
}
public function testYearDisplay() {
// Create test entries
$entry2020 = new RawBibEntry();
$entry2020->setField('year', '2020');
$entry2020->setField('title', 'Paper 2020');
$entry2020->setField('author', 'Author A');
// assert getKey
$this->assertEquals('97c46f8bdf428ce28cfa05cdedba2ec1', $entry2020->getKey());
$entry2019a = new RawBibEntry();
$entry2019a->setField('year', '2019');
$entry2019a->setField('title', 'Paper 2019 A');
$entry2019a->setField('author', 'Author B');
$entry2019b = new RawBibEntry();
$entry2019b->setField('year', '2019');
$entry2019b->setField('title', 'Paper 2019 B');
$entry2019b->setField('author', 'Author C');
// Create YearDisplay
$display = new YearDisplay();
// Set test entries
$entries = array(
'key2020' => $entry2020,
'key2019a' => $entry2019a,
'key2019b' => $entry2019b
);
$display->setEntries($entries);
// Get year index and verify
$yearIndex = $display->yearIndex;
$this->assertEquals("2020", $yearIndex[2020]);
// Capture output
ob_start();
$display->display();
$output = ob_get_clean();
// Verify output contains years and titles
// split output by line
$lines = explode("\n", $output);
$this->assertEquals('<div class="theader">2020</div><table class="result">', $lines[0]);
}
public function testXMLPrettyPrinter() {
// Create sample BibTeX entry with various fields to test
$bibtex = "@article{test2023,
author = {Test Author},
title = {A Test Title with Special Characters: & < >},
journal = {Test Journal},
year = {2023},
volume = {1},
number = {2},
pages = {100--200}
}";
// Set up input stream with BibTeX content
$stream = fopen('php://memory', 'r+');
fwrite($stream, $bibtex);
rewind($stream);
// Create XMLPrettyPrinter and parse
$printer = new XMLPrettyPrinter();
$printer->header = false;
$parser = new StateBasedBibtexParser($printer);
// Capture output
ob_start();
$parser->parse($stream);
$output = ob_get_clean();
// Verify XML structure and content
$this->assertStringContainsString('<?xml version="1.0"', $output);
$this->assertStringContainsString('<bibfile>', $output);
$this->assertStringContainsString('</bibfile>', $output);
// Verify entry type
$this->assertStringContainsString('<type>article</type>', $output);
// Verify fields are present
$this->assertStringContainsString('<key>author</key>', $output);
$this->assertStringContainsString('<value>Test Author</value>', $output);
// Verify special characters are escaped
$this->assertStringContainsString('&amp;', $output);
$this->assertStringContainsString('&lt;', $output);
$this->assertStringContainsString('&gt;', $output);
fclose($stream);
}
public function testBibtexDisplay() {
// Create test entries
$entry1 = new RawBibEntry();
$entry1->setType('article');
$entry1->setField('title', 'Test Title');
$entry1->setField('author', 'Test Author');
$entry1->setField('year', '2023');
$entry1->setField('journal', 'Test Journal');
$entry2 = new RawBibEntry();
$entry2->setType('inproceedings');
$entry2->setField('title', 'Another Title with Special Chars: é');
$entry2->setField('author', 'Another Author');
$entry2->setField('year', '2022');
$entry2->setField('booktitle', 'Test Conference');
// Create BibtexDisplay instance
$display = new BibtexDisplay();
$display->header = false;
$display->setTitle('Test Export');
$display->setEntries(array($entry1, $entry2));
// assert entries in $display
$this->assertEquals(2, count($display->entries));
// set BIBTEXBROWSER_BIBTEX_VIEW to reconstructed
bibtexbrowser_configure('BIBTEXBROWSER_BIBTEX_VIEW', 'reconstructed');
// Capture output
ob_start();
$display->display();
$output = ob_get_clean();
// Verify output contains expected elements
// Header comments
$this->assertStringContainsString('% generated by bibtexbrowser', $output);
$this->assertStringContainsString('% Test Export', $output);
$this->assertStringContainsString('% Encoding: UTF-8', $output);
// Entry 1 content
$this->assertStringContainsString('@article{', $output);
$this->assertStringContainsString('title = {Test Title}', $output);
$this->assertStringContainsString('author = {Test Author}', $output);
$this->assertStringContainsString('year = {2023}', $output);
$this->assertStringContainsString('journal = {Test Journal}', $output);
// Entry 2 content
$this->assertStringContainsString('@inproceedings{', $output);
$this->assertStringContainsString('title = {Another Title with Special Chars: é}', $output);
$this->assertStringContainsString('author = {Another Author}', $output);
$this->assertStringContainsString('year = {2022}', $output);
$this->assertStringContainsString('booktitle = {Test Conference}', $output);
}
public function testCreateBibEntryDisplay() {
// Test instance creation
$display = createBibEntryDisplay();
$this->assertInstanceOf('BibEntryDisplay', $display);
// Create test entry
$entry = new RawBibEntry();
$entry->setType('article');
$entry->setField('title', 'Test Title');
$entry->setField('author', 'Test Author');
$entry->setField('year', '2023');
$entry->setField('journal', 'Test Journal');
$entry->setField('abstract', 'Test Abstract');
$entry->setField('url', 'http://example.com');
// assertion on toString
$this->assertEquals('article 4a9ba73904f4f22a7b37e18750ee5454', $entry->__toString());
// Test display with entry
$display->setEntries(array($entry));
// Capture output
ob_start();
$display->display();
$output = ob_get_clean();
// Verify display output contains expected elements
$this->assertStringContainsString('Test Title', $output);
$this->assertStringContainsString('Test Author', $output);
$this->assertStringContainsString('Test Journal', $output);
$this->assertStringContainsString('Test Abstract', $output);
// Test metadata generation
$metadata = $display->metadata();
$this->assertIsArray($metadata);
// Verify metadata contains essential fields
$foundTitle = false;
$foundAuthor = false;
foreach($metadata as $meta) {
if($meta[0] == 'citation_title' && $meta[1] == 'Test Title') {
$foundTitle = true;
}
if($meta[0] == 'citation_author' && $meta[1] == 'Author, Test') {
$foundAuthor = true;
}
}
$this->assertTrue($foundTitle);
$this->assertTrue($foundAuthor);
// Test title generation
$this->assertEquals('Test Title (bibtex)', $display->getTitle());
}
public function testParserDelegate() {
// Create test delegate
$delegate = new TestParserDelegate();
// Create parser with delegate
$parser = new StateBasedBibtexParser($delegate);
// Create test bibtex content
$bibtex = "@article{test2023,
author = {Test Author},
title = {Test Title},
journal = {Test Journal},
year = {2023},
abstract = {Test Abstract}
}";
// Create memory stream with test content
$stream = fopen('php://memory', 'r+');
fwrite($stream, $bibtex);
rewind($stream);
// Parse the content
$parser->parse($stream);
// Verify event sequence
$expected = array(
'beginFile',
'beginEntry',
'setEntryType:article',
'setEntryKey:test2023',
'setEntryField:author:Test Author',
'setEntryField:title:Test Title',
'setEntryField:journal:Test Journal',
'setEntryField:year:2023',
'setEntryField:abstract:Test Abstract',
'endEntry',
'endFile'
);
$this->assertEquals($expected, $delegate->events);
fclose($stream);
}
public function testRSSDisplay() {
// Create test entries with various data to test RSS generation
$entry1 = new RawBibEntry();
$entry1->setType('article');
$entry1->setField('title', 'Test Title with Special Chars: & < >');
$entry1->setField('author', 'Test Author');
$entry1->setField('year', '2023');
$entry1->setField('journal', 'Test Journal');
$entry1->setField('abstract', 'Test Abstract with HTML <b>tags</b>');
$entry1->setField('url', 'http://example.com');
$entry2 = new RawBibEntry();
$entry2->setType('inproceedings');
$entry2->setField('title', 'Another Test Title');
$entry2->setField('author', 'Another Author');
$entry2->setField('year', '2022');
$entry2->setField('booktitle', 'Test Conference');
// Create RSSDisplay instance
$display = new RSSDisplay();
$display->header = false;
$display->setTitle('Test RSS Feed');
$display->setEntries(array($entry1, $entry2));
// Capture output
ob_start();
$display->display();
$output = ob_get_clean();
// Verify XML declaration
$this->assertStringContainsString('<?xml version="1.0" encoding="UTF-8"?>', $output);
// Verify RSS structure
$this->assertStringContainsString('<rss version="2.0"', $output);
$this->assertStringContainsString('<channel>', $output);
$this->assertStringContainsString('<title>Test RSS Feed</title>', $output);
// Verify entries
$this->assertStringContainsString('<item>', $output);
$this->assertStringContainsString('Test Title with Special Chars: &#38; &#60; &#62;', $output);
$this->assertStringContainsString('Another Test Title', $output);
// Verify text encoding
$rss = $display->text2rss('Test & Text <b>bold</b> with HTML &eacute;');
$this->assertEquals('Test &#38; Text bold with HTML ', $rss);
// Verify metadata handling
$this->assertStringContainsString('<description>', $output);
$this->assertStringContainsString('<link>', $output);
$this->assertStringContainsString('<guid', $output);
// Verify valid XML
$xml = new SimpleXMLElement($output);
$this->assertInstanceOf('SimpleXMLElement', $xml);
}
public function testHTMLTemplate() {
// Create mock content object that implements required methods
$mockContent = new class {
public function display() {
echo '<div class="test-content">Test Content</div>';
}
public function getTitle() {
return 'Test Title';
}
public function metadata() {
return array(
array('description', 'Test Description'),
array('keywords', 'test, bibtex')
);
}
};
// Capture output
bibtexbrowser_configure('BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT', true);
ob_start();
HTMLTemplate($mockContent, false);
$output = ob_get_clean();
// Verify basic HTML structure
$this->assertStringContainsString('<!DOCTYPE html PUBLIC', $output);
$this->assertStringContainsString('<html xmlns="http://www.w3.org/1999/xhtml">', $output);
$this->assertStringContainsString('</html>', $output);
// Verify HEAD section
$this->assertStringContainsString('<meta http-equiv="Content-Type" content="text/html; charset=', $output);
$this->assertStringContainsString('<meta name="generator" content="bibtexbrowser', $output);
// Verify meta tags
$this->assertStringContainsString('<meta name="description" property="description" content="Test Description"', $output);
$this->assertStringContainsString('<meta name="keywords" property="keywords" content="test, bibtex"', $output);
// Verify title
$this->assertStringContainsString('<title>Test Title</title>', $output);
// Verify CSS inclusion
$this->assertStringContainsString('<style type="text/css">', $output);
// Verify content display
$this->assertStringContainsString('<div class="test-content">Test Content</div>', $output);
// Verify JavaScript includes when progressive enhancement enabled
$this->assertStringContainsString(JQUERY_URI, $output);
}
} // end class
// Test implementation that records events
class TestParserDelegate extends ParserDelegate {
public $events = array();
function beginFile() {
$this->events[] = 'beginFile';
}
function endFile() {
$this->events[] = 'endFile';
}
function setEntryField($key, $value) {
$this->events[] = "setEntryField:".trim($key).":".trim($value);
}
function setEntryType($type) {
$this->events[] = "setEntryType:$type";
}
function setEntryKey($key) {
$this->events[] = "setEntryKey:$key";
}
function beginEntry() {
$this->events[] = 'beginEntry';
}
function endEntry($source) {
$this->events[] = 'endEntry';
}
}
@copy('bibtexbrowser.local.php.bak','bibtexbrowser.local.php');
?>

61
bibtexbrowser.php

@ -728,7 +728,9 @@ class StateBasedBibtexParser {
} // end function
} // end class
/** a default empty implementation of a delegate for StateBasedBibtexParser */
/** a default empty implementation of a delegate for StateBasedBibtexParser
* @codeCoverageIgnore
*/
class ParserDelegate {
function beginFile() {}
@ -758,18 +760,20 @@ usage:
see snippet of [[#StateBasedBibParser]]
*/
class XMLPrettyPrinter extends ParserDelegate {
var $header = true;
function beginFile() {
header('Content-type: text/xml;');
if ($this->header) {
header('Content-type: text/xml;');
}
print '<?xml version="1.0" encoding="'.OUTPUT_ENCODING.'"?>';
print '<bibfile>';
}
function endFile() {
print '</bibfile>';
}
function setEntryField($finalkey,$entryvalue) {
print "<data>\n<key>".$finalkey."</key>\n<value>".$entryvalue."</value>\n</data>\n";
print "<data>\n<key>".trim($finalkey)."</key>\n<value>".htmlspecialchars($entryvalue)."</value>\n</data>\n";
}
function setEntryType($entrytype) {
@ -1148,6 +1152,7 @@ function s3988($s) {
see BibEntry->formatAuthor($author)
@deprecated
@nodoc
@codeCoverageIgnore
*/
function formatAuthor() {
die('Sorry, this function does not exist anymore, however, you can simply use $bibentry->formatAuthor($author) instead.');
@ -1191,7 +1196,7 @@ class BibEntry {
var $timestamp;
/** The name of the file containing this entry */
var $filename;
var $filename = "nofilename-frommemory";
/** The short name of the entry (parameterized by ABBRV_TYPE) */
var $abbrv;
@ -1231,7 +1236,9 @@ class BibEntry {
/** Returns the type of this bib entry (always lowercase). */
function getType() {
// strtolower is important to be case-insensitive
return strtolower($this->getField(Q_INNER_TYPE));
$res = $this->getField(Q_INNER_TYPE);
if ($res == NULL) return 'unknown';
return strtolower($res);
}
/** Sets the key of this bib entry. */
@ -1467,6 +1474,10 @@ class BibEntry {
/** Returns the key of this entry */
function getKey() {
if ($this->getField(Q_KEY) == null) {
$key = md5($this->getTitle().$this->getFormattedAuthorsString());
$this->setField(Q_KEY, $key);
}
return $this->getField(Q_KEY);
}
@ -2071,6 +2082,7 @@ class BibEntry {
} // end class BibEntry
class RawBibEntry extends BibEntry {
function setField($name, $value) {
$this->fields[$name]=$value;
$this->raw_fields[$name]=$value;
@ -3168,6 +3180,7 @@ class YearDisplay {
/** is an array of strings representing years */
var $yearIndex;
var $entries;
function setDB($bibdatabase) {
$this->setEntries($bibdatabase->bibdb);
@ -4303,11 +4316,13 @@ usage:
getTitle()
* $title: title of the page
*/
function HTMLTemplate($content) {
function HTMLTemplate($content, $header = true) {
// when we load a page with AJAX
// the HTTP header is taken into account, not the <meta http-equiv>
header('Content-type: text/html; charset='.OUTPUT_ENCODING);
if ($header) {
header('Content-type: text/html; charset='.OUTPUT_ENCODING);
}
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
?>
@ -4406,7 +4421,9 @@ usage:
</pre>
*/
class BibtexDisplay {
var $header = true;
var $entries;
var $title;
function __construct() {}
function setTitle($title) { $this->title = $title; return $this; }
@ -4419,7 +4436,9 @@ class BibtexDisplay {
function setWrapper($x) { $x->wrapper = 'NoWrapper'; }
function display() {
header('Content-type: text/plain; charset='.OUTPUT_ENCODING);
if ($this->header) {
header('Content-type: text/plain; charset='.OUTPUT_ENCODING);
}
echo '% generated by bibtexbrowser <http://www.monperrus.net/martin/bibtexbrowser/>'."\n";
echo '% '.@$this->title."\n";
echo '% Encoding: '.OUTPUT_ENCODING."\n";
@ -4534,7 +4553,8 @@ usage:
class RSSDisplay {
var $title = 'RSS produced by bibtexbrowser';
var $header = true;
var $entries;
function __construct() {
// nothing by default
}
@ -4558,6 +4578,7 @@ class RSSDisplay {
// be careful of <
$desc = str_replace('<','&#60;',$desc);
$desc = str_replace('>','&#62;',$desc);
// final test with encoding:
if (function_exists('mb_check_encoding')) { // (PHP 4 >= 4.4.3, PHP 5 >= 5.1.3)
@ -4577,7 +4598,9 @@ class RSSDisplay {
function setWrapper($x) { $x->wrapper = 'NoWrapper'; }
function display() {
header('Content-type: application/rss+xml');
if ($this->header) {
header('Content-type: application/rss+xml');
}
echo '<?xml version="1.0" encoding="'.OUTPUT_ENCODING.'"?>';
//
@ -4585,8 +4608,8 @@ class RSSDisplay {
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title><?php echo $this->title;?></title>
<link>http://<?php echo @$_SERVER['HTTP_HOST'].htmlentities(@$_SERVER['REQUEST_URI']);?></link>
<atom:link href="http://<?php echo @$_SERVER['HTTP_HOST'].htmlentities(@$_SERVER['REQUEST_URI']);?>" rel="self" type="application/rss+xml" />
<link>http://<?php echo getServerData('HTTP_HOST').htmlentities(getServerData('REQUEST_URI'));?></link>
<atom:link href="http://<?php echo getServerData('HTTP_HOST').htmlentities(getServerData('REQUEST_URI'));?>" rel="self" type="application/rss+xml" />
<description></description>
<generator>bibtexbrowser v__GITHUB__</generator>
@ -4613,6 +4636,16 @@ class RSSDisplay {
}
}
/**
* workaround deprecation
*/
function getServerData($key) {
// if exists
if (isset($_SERVER[$key])) {
return $_SERVER[$key];
}
return "";
}
/** is responsible for transforming a query string of $_GET[..] into a publication list.

Loading…
Cancel
Save