Chronicles of a build - the theme framework 03

Keeping in mind the folder and namespacing structure I outlined in my earlier post I will move to define, via unit-tests, the expected outputs the Main class will generate in various problematic situations; I want the Main class to send messages in place of raising exceptions and errors and will start from the case where no /controllers sub-folder is found or no controllers are found in the /controllers sub-folder. To test for this cases I’ve setup a sandbox folder in the /tests folder to simulate various scenarios, the /tests/sandbox folder has the following structure

tests/sandbox
|   /aloneMain
|   |   AloneMain.php // defines the \TAD\Test\AloneMain class
|   /badNamesControllers
|   |   MainWithBadlyNamedControllers.php // defines the \TAD\Test\MainWithBadlyNamedControllers class
|   |   /controllers
|   |   |   Baz.php
|   |   |   Foo.php
|   /emptyControllersFolder
|   |   MainWithEmptyControllersFolder.php // defines the \TAD\Test\MainWithEmptyControllersFolder class
|   |   /controllers

And the tests, in the file tests/MainTest.php, are

    public function testCallingShowOnMainMissingControllersFolderReturnsMessage()
{
    // I expect the calling to return a message about a missing controllers folder
    $regex = "/.*controllers folder.*?/uUs";
    $this->expectOutputRegex($regex);
    // main file sitting alone in a folder
    \TAD\Test\AloneMain::show('SomeController');
}
public function testCallingShowOnMainWithEmptyControllersFolderReturnsMessage()
{
    // I expect the calling to return a message about an empty controllers folder
    $regex = "/.*controllers folder.*empty.*?/uUs";
    $this->expectOutputRegex($regex);
    // main file sitting alone in a folder
    \TAD\Test\MainWithEmptyControllersFolder::show('SomeController');
}
public function testCallingShowOnMainWithNotWellNamedControllersReturnsMessage()
{
    // I expect the calling to return a message about controllers not sticking to the naming convention
    $regex = "/.*not.*properly named controller files.*?/uUs";
    $this->expectOutputRegex($regex);
    // main file sitting alone in a folder
    \TAD\Test\MainWithBadlyNamedControllers::show('SomeController');
}
public function _after()
{
    Main::reset();
}

Please note that I use the Main::reset method after each test.

Testing some other minor methods

I’m not going for full code-coverage here and will implement some more test for the Main class on minor get/set methods to make them pretty safe. More light headed users will interact with the framework using mainly the show method so throwing exceptions here makes sense, in test code I write

 public function testGetControllerReturnsNullForNonIndexOrNullControllers()
{
    $this->assertNull(TestMain::getController('foo'));
    TestMain::maybeInit();
    $this->assertNull(TestMain::getController('foo'));
}
public function testGetControllerReturnsController()
{
    TestMain::maybeInit();
    $this->assertNotNull(TestMain::getController('First'));
}
public function testSetControllerSetsObjectAndUnsets()
{
    $object = (object)'some';
    TestMain::setController('some', $object);
    $r = TestMain::getController('some');
    $this->assertSame($object, TestMain::getController('some'));
    TestMain::setController('some');
    $this->assertNull(TestMain::getController('some'));
}
public function testGetControllersReturnsNullForNonInitializedControllers()
{
    $this->assertNull(TestMain::getControllers());
}
public function testSetControllersWillSetControllers()
{
    $ar = array(
        'foo' => (object)'foo',
        'baz' => (object)'baz',
        'bar' => (object)'bar'
    );
    TestMain::setControllers($ar);

    foreach ($ar as $key => $value) {
        $this->assertEquals($value, TestMain::getController($key));
    }
}
public function testSetControllerThrowsForNonStringKey()
{
    $this->setExpectedException('InvalidArgumentException');
    TestMain::setController(1, 'some');
}
public function testSetControllerWillThrowForNonObjects()
{
    $this->setExpectedException('InvalidArgumentException');
    TestMain::setController('some', 'some');
}
public function testSetControllersWillThrowForNonArrayArgument()
{
    $this->setExpectedException('InvalidArgumentException');
    TestMain::setControllers('foo');
}
public function testSetControllersWillUnsetControllersWithNullArgument()
{
    $a = array(
        'some',
        'baz',
        'bar'
    );

    foreach ($a as $key) {
        TestMain::setController($key, (object)$key);
    }
    $this->assertNotNull(TestMain::getControllers());
    TestMain::setControllers();
    $this->assertNull(TestMain::getControllers());
}

And after some red and green lighting will end up with the code (that can be found on GitHub)

public static function setControllers($controllers = null)
{
    if (!is_null($controllers) and !is_array($controllers)) {

        throw new \InvalidArgumentException('Controllers must either be an array or null');
    }
    if (is_null($controllers)) {
        self::$controllers = null;
        return;
    }

    foreach ($controllers as $key => $value) {
        self::setController($key, $value);
    }
}
public static function getControllers()
{

    return self::$controllers;
}
public static function setController($key, $value = null)
{
    if (!is_string($key)) {

        throw new \InvalidArgumentException('Key must be a string');
    }
    if (!is_null($value) and !is_object($value)) {

        throw new \InvalidArgumentException('Value must be an object');
    }
    if (self::$controllers === null) {
        self::$controllers = array();
    }
    self::$controllers[$key] = $value;
}
public static function getController($key)
{
    if (null === self::$controllers or !in_array($key, array_keys(self::$controllers))) {

        return null;
    }

    return self::$controllers[$key];
}

I will move, then, to the Controller class.