From 4bac766e3869edbf917e792d1a3b71346ade21a9 Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Wed, 27 Jun 2012 10:24:47 -0400
Subject: [PATCH] Began setting up unit testing infrastructure; ported over
 ISBN code as a first test case.

---
 module/VuFind/src/VuFind/Code/ISBN.php | 205 +++++++++++++++++++++++++
 module/VuFind/tests/Code/ISBNTest.php  | 123 +++++++++++++++
 tests/bootstrap.php                    |  38 +++++
 tests/phpunit.xml                      |  13 ++
 4 files changed, 379 insertions(+)
 create mode 100644 module/VuFind/src/VuFind/Code/ISBN.php
 create mode 100644 module/VuFind/tests/Code/ISBNTest.php
 create mode 100644 tests/bootstrap.php
 create mode 100644 tests/phpunit.xml

diff --git a/module/VuFind/src/VuFind/Code/ISBN.php b/module/VuFind/src/VuFind/Code/ISBN.php
new file mode 100644
index 00000000000..fda87d0dcab
--- /dev/null
+++ b/module/VuFind/src/VuFind/Code/ISBN.php
@@ -0,0 +1,205 @@
+<?php
+/**
+ * ISBN validation and conversion functionality
+ *
+ * PHP version 5
+ *
+ * Copyright (c) Demian Katz 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Support_Classes
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://www.vufind.org  Main Page
+ */
+namespace VuFind\Code;
+
+/**
+ * ISBN Class
+ *
+ * This class provides ISBN validation and conversion functionality.
+ *
+ * @category VuFind2
+ * @package  Support_Classes
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://www.vufind.org  Main Page
+ */
+class ISBN
+{
+    protected $raw;
+    protected $valid = null;
+
+    /**
+     * Constructor
+     *
+     * @param string $raw Raw ISBN string to convert/validate.
+     */
+    public function __construct($raw)
+    {
+        // Strip out irrelevant characters:
+        $this->raw = self::normalizeISBN($raw);
+    }
+
+    /**
+     * Get the ISBN in ISBN-10 format:
+     *
+     * @return mixed ISBN, or false if invalid/incompatible.
+     */
+    public function get10()
+    {
+        // Is it valid?
+        if ($this->isValid()) {
+            // Is it already an ISBN-10?  If so, return as-is.
+            if (strlen($this->raw) == 10) {
+                return $this->raw;
+            } else if (strlen($this->raw) == 13
+                && substr($this->raw, 0, 3) == '978'
+            ) {
+                // Is it a Bookland EAN?  If so, we can convert to ISBN-10.
+                $start = substr($this->raw, 3, 9);
+                return $start . self::getISBN10CheckDigit($start);
+            }
+        }
+        
+        // If we made it this far, conversion was not possible:
+        return false;
+    }
+
+    /**
+     * Get the ISBN in ISBN-13 format:
+     *
+     * @return mixed ISBN, or false if invalid/incompatible.
+     */
+    public function get13()
+    {
+        // Is it valid?
+        if ($this->isValid()) {
+            // Is it already an ISBN-13?  If so, return as-is.
+            if (strlen($this->raw) == 13) {
+                return $this->raw;
+            } else if (strlen($this->raw) == 10) {
+                // Is it an ISBN-10?  If so, convert to Bookland EAN:
+                $start = '978' . substr($this->raw, 0, 9);
+                return $start . self::getISBN13CheckDigit($start);
+            }
+        }
+        
+        // If we made it this far, conversion was not possible:
+        return false;
+    }
+
+    /**
+     * Is the current ISBN valid in some format?  (May be 10 or 13 digit).
+     *
+     * @return boolean
+     */
+    public function isValid()
+    {
+        // If we haven't already checked validity, do so now and store the result:
+        if (is_null($this->valid)) {
+            if (self::isValidISBN10($this->raw)
+                || self::isValidISBN13($this->raw)
+            ) {
+                $this->valid = true;
+            } else {
+                $this->valid = false;
+            }
+        }
+        return $this->valid;
+    }
+
+    /**
+     * Strip extraneous characters and whitespace from an ISBN.
+     *
+     * @param string $raw ISBN to clean up.
+     *
+     * @return string     Normalized ISBN.
+     */
+    public static function normalizeISBN($raw)
+    {
+        return preg_replace('/[^0-9X]/', '', strtoupper($raw));
+    }
+
+    /**
+     * Given the first 9 digits of an ISBN-10, generate the check digit.
+     *
+     * @param string $isbn The first 9 digits of an ISBN-10.
+     *
+     * @return string      The check digit.
+     */
+    public static function getISBN10CheckDigit($isbn)
+    {
+        $sum = 0;
+        for ($x = 0; $x < strlen($isbn); $x++) {
+            $sum += intval(substr($isbn, $x, 1)) * (1 + $x);
+        }
+        $checkdigit = $sum % 11;
+        return $checkdigit == 10 ? 'X' : $checkdigit;
+    }
+
+    /**
+     * Is the provided ISBN-10 valid?
+     *
+     * @param string $isbn The ISBN-10 to test.
+     *
+     * @return boolean
+     */
+    public static function isValidISBN10($isbn)
+    {
+        $isbn = self::normalizeISBN($isbn);
+        if (strlen($isbn) != 10) {
+            return false;
+        }
+        return (substr($isbn, 9) == self::getISBN10CheckDigit(substr($isbn, 0, 9)));
+    }
+
+    /**
+     * Given the first 12 digits of an ISBN-13, generate the check digit.
+     *
+     * @param string $isbn The first 12 digits of an ISBN-13.
+     *
+     * @return string      The check digit.
+     */
+    public static function getISBN13CheckDigit($isbn)
+    {
+        $sum = 0;
+        $weight = 1;
+        for ($x = 0; $x < strlen($isbn); $x++) {
+            $sum += intval(substr($isbn, $x, 1)) * $weight;
+            $weight = $weight == 1 ? 3 : 1;
+        }
+        $retval = 10 - ($sum % 10);
+        return $retval == 10 ? 0 : $retval;
+    }
+
+    /**
+     * Is the provided ISBN-13 valid?
+     *
+     * @param string $isbn The ISBN-13 to test.
+     *
+     * @return boolean
+     */
+    public static function isValidISBN13($isbn)
+    {
+        $isbn = self::normalizeISBN($isbn);
+        if (strlen($isbn) != 13) {
+            return false;
+        }
+        return
+            (substr($isbn, 12) == self::getISBN13CheckDigit(substr($isbn, 0, 12)));
+    }
+}
diff --git a/module/VuFind/tests/Code/ISBNTest.php b/module/VuFind/tests/Code/ISBNTest.php
new file mode 100644
index 00000000000..bd49969fdf2
--- /dev/null
+++ b/module/VuFind/tests/Code/ISBNTest.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * ISBN Test Class
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Tests
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/unit_tests Wiki
+ */
+namespace VuFind\Tests;
+use VuFind\Code\ISBN;
+
+/**
+ * ISBN Test Class
+ *
+ * @category VuFind2
+ * @package  Tests
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Chris Hallberg <challber@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/unit_tests Wiki
+ */
+class ISBNTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Test Valid ISBN-10.
+     *
+     * @return void
+     */
+    public function testValidISBN10()
+    {
+        $isbn = new ISBN('0123456789');
+        $this->assertEquals($isbn->get10(), '0123456789');
+        $this->assertEquals($isbn->get13(), '9780123456786');
+        $this->assertTrue($isbn->isValid());
+    }
+
+    /**
+     * Test Valid ISBN-13.
+     *
+     * @return void
+     */
+    public function testValidISBN13()
+    {
+        $isbn = new ISBN('9780123456786');
+        $this->assertEquals($isbn->get10(), '0123456789');
+        $this->assertEquals($isbn->get13(), '9780123456786');
+        $this->assertTrue($isbn->isValid());
+    }
+
+    /**
+     * Test Valid ISBN-10 with dashes.
+     *
+     * @return void
+     */
+    public function testValidISBN10WithDashes()
+    {
+        $isbn = new ISBN('0-12-345678-9');
+        $this->assertEquals($isbn->get10(), '0123456789');
+        $this->assertEquals($isbn->get13(), '9780123456786');
+        $this->assertTrue($isbn->isValid());
+    }
+
+    /**
+     * Test Valid ISBN-13 with dashes.
+     *
+     * @return void
+     */
+    public function testValidISBN13WithDashes()
+    {
+        // Valid ISBN-13 with dashes:
+        $isbn = new ISBN('978-0-12-345678-6');
+        $this->assertEquals($isbn->get10(), '0123456789');
+        $this->assertEquals($isbn->get13(), '9780123456786');
+        $this->assertTrue($isbn->isValid());
+    }
+
+    /**
+     * Test Valid ISBN-13 that is not part of the Bookland EAN.
+     *
+     * @return void
+     */
+    public function testValidISBN13OutsideOfBooklandEAN()
+    {
+        // Valid ISBN-13 outside of Bookland EAN:
+        $isbn = new ISBN('9790123456785');
+        $this->assertEquals($isbn->get10(), false);
+        $this->assertEquals($isbn->get13(), '9790123456785');
+        $this->assertTrue($isbn->isValid());
+    }
+
+    /**
+     * Test Invalid ISBN-10.
+     *
+     * @return void
+     */
+    public function testInvalidISBN10()
+    {
+        // Invalid ISBN-10:
+        $isbn = new ISBN('2314346323');
+        $this->assertEquals($isbn->get10(), false);
+        $this->assertEquals($isbn->get13(), false);
+        $this->assertFalse($isbn->isValid());
+    }
+}
\ No newline at end of file
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 00000000000..d7c7afba72d
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,38 @@
+<?php
+use Zend\Loader\AutoloaderFactory;
+use Zend\ServiceManager\ServiceManager;
+use Zend\Mvc\Service\ServiceManagerConfiguration;
+
+// Set flag that we're in test mode
+define('VUFIND_PHPUNIT_RUNNING', 1);
+
+// Define path to application directory
+defined('APPLICATION_PATH')
+    || define('APPLICATION_PATH', dirname(__DIR__));
+
+// Define application environment
+defined('APPLICATION_ENV')
+    || define('APPLICATION_ENV', (getenv('VUFIND_ENV') ? getenv('VUFIND_ENV') : 'testing'));
+
+// Define path to local override directory
+defined('LOCAL_OVERRIDE_DIR')
+    || define('LOCAL_OVERRIDE_DIR', (getenv('VUFIND_LOCAL_DIR') ? getenv('VUFIND_LOCAL_DIR') : ''));
+
+chdir(APPLICATION_PATH);
+
+// Composer autoloading
+if (file_exists('vendor/autoload.php')) {
+    $loader = include 'vendor/autoload.php';
+}
+
+if (!class_exists('Zend\Loader\AutoloaderFactory')) {
+    throw new RuntimeException('Unable to load ZF2.');
+}
+
+// Get application stack configuration
+$configuration = include 'config/application.config.php';
+
+// Setup service manager
+$serviceManager = new ServiceManager(new ServiceManagerConfiguration($configuration['service_manager']));
+$serviceManager->setService('ApplicationConfiguration', $configuration);
+$serviceManager->get('ModuleManager')->loadModules();
\ No newline at end of file
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
new file mode 100644
index 00000000000..78b63f11402
--- /dev/null
+++ b/tests/phpunit.xml
@@ -0,0 +1,13 @@
+<phpunit bootstrap="./bootstrap.php" backupGlobals="false">
+  <testsuites>
+    <testsuite name="VuFind">
+      <directory>../module/VuFind/tests</directory>
+    </testsuite>
+  </testsuites>
+
+  <filter>
+    <whitelist addUncoveredFilesFromWhitelist="true">
+      <directory suffix=".php">../module/VuFind/src</directory>
+    </whitelist>
+  </filter>
+</phpunit>
-- 
GitLab