14.5. Schema Loader Testing

A Schema Loader will build a schema from a variety of sources.

For the essential implementation, see Schema Loader Module – Load Embedded or External Schema.

Also, we will have schemata written in COBOL notation, but that’s handled separately.

14.5.1. Overheads

"""stingray.schema.loader Unit Tests."""
import unittest
import stingray.schema
import stingray.sheet
import stingray.schema.loader

First, we define mock classes.

MockWorkbook class implements a minimal interface that a sheet.Sheet can rely on.

class SheetMockWorkbook:
    def rows_of( self, sheet ):
        self.requested= sheet.name
        return iter( self.rows )
    def sheet( self, name, sheet_type, **kw ):
        return self.mock_sheet

MockSheet class implements a minimal interface that a sheet.Row can rely on.

class MockSheet:
    def __init__( self, workbook, sheet_name ):
        self.workbook, self.name= workbook, sheet_name
    def schema( self ):
        return self.mock_schema
    def rows( self ):
        return self.workbook.rows_of( self )

MockRow class implements a minimal interface that collects cell instances.

class MockRow:
    def __init__( self, sheet, *data ):
        self.sheet= sheet
        self.data= data
    def cell( self, attribute ):
        return self.data[attribute.position]
    def __iter__( self ):
        return iter(self.data)

14.5.2. HeadingRowSchemaLoader Tests

A schema.loader.SchemaLoader` is abstract, and doesn’t require much independent testing.

A schema.loader.HeadingRowSchemaLoader builds a schema.Schema from the first row from a sheet.Sheet.

class TestHeadingRowSchemaParser( unittest.TestCase ):
    def setUp( self ):
        self.wb= SheetMockWorkbook( )
        self.sheet= MockSheet( self.wb, 'The_Name' )
        self.wb.rows = [
            MockRow( self.sheet, stingray.cell.TextCell("Col 1", self.wb),
              stingray.cell.TextCell("Col 2", self.wb) ),
            MockRow( self.sheet, stingray.cell.NumberCell(1, self.wb),
              stingray.cell.TextCell("First", self.wb) ),
            MockRow( self.sheet, stingray.cell.NumberCell(2, self.wb),
              stingray.cell.TextCell("Second", self.wb), ),
            ]
        self.parser= stingray.schema.loader.HeadingRowSchemaLoader( self.sheet )
    def test_should_parse( self ):
        schema = self.parser.schema()
        self.assertEqual( 2, len(schema) )
        self.assertEqual( "Col 1", schema[0].name )
        self.assertEqual( "Col 2", schema[1].name )
        rows = list( self.parser.rows() )
        self.assertEqual( 2, len(rows) )

14.5.3. ExternalSchemaLoader

An schema.loader.ExternalSchemaLoader builds a schema.Schema from another workbook.base.Workbook.

class TestExternalSchemaLoader( unittest.TestCase ):
    def setUp( self ):
        self.wb= SheetMockWorkbook( )
        self.wb.mock_sheet= MockSheet( self.wb, 'The_Name' )
        self.wb.mock_sheet.schema = stingray.schema.Schema(
            stingray.schema.Attribute("name",create=stingray.cell.TextCell),
            stingray.schema.Attribute("offset",create=stingray.cell.NumberCell),
            stingray.schema.Attribute("size",create=stingray.cell.NumberCell),
            stingray.schema.Attribute("type",create=stingray.cell.TextCell),
        )
        sheet= self.wb.mock_sheet
        self.wb.rows = [
            #MockRow( sheet, stingray.cell.TextCell("name", self.wb),
            #  stingray.cell.TextCell("offset", self.wb),
            #  stingray.cell.TextCell("size", self.wb),
            #  stingray.cell.TextCell("type", self.wb),
            #  ),
            MockRow( sheet, stingray.cell.TextCell("Col 1", self.wb),
              stingray.cell.NumberCell(1, self.wb),
              stingray.cell.NumberCell(5, self.wb),
              stingray.cell.TextCell("str", self.wb ),
              ),
            MockRow( sheet, stingray.cell.TextCell("Col 2", self.wb),
              stingray.cell.NumberCell(6, self.wb),
              stingray.cell.NumberCell(10, self.wb),
              stingray.cell.TextCell("str", self.wb),
              ),
            ]

        self.loader= stingray.schema.loader.ExternalSchemaLoader( self.wb, 'The_Name',)
    def test_should_parse( self ):
        schema = self.loader.schema()
        self.assertEqual( 2, len(schema) )
        self.assertEqual( "Col 1", schema[0].name )
        self.assertEqual( "Col 2", schema[1].name )

14.5.4. ExternalSchemaSheet Tests

The sheet.ExternalSchemaSheet creates a schema from an external source, usually another Workbook.

An external schema can be loaded using an schema.loader.ExternalSchemaLoader. However, we can also hard-code a Schema. Or build it some other way.

A workbook.base.Workbook uses this type to build each individual sheet.Sheet, attaching the schema (and column titles, etc.) to each sheet.Row that gets built.

class TestExternalSchemaSheet( unittest.TestCase ):
    def setUp( self ):
        self.wb= SheetMockWorkbook( )
        schema = stingray.schema.Schema(
            stingray.schema.Attribute( "Col 1" ),
            stingray.schema.Attribute( "Col 2" ),
        )
        self.sheet= stingray.sheet.ExternalSchemaSheet( self.wb, 'The_Name', schema=schema )
        self.wb.rows = [
            MockRow( self.sheet, stingray.cell.NumberCell(1, self.wb),
              stingray.cell.TextCell("First", self.wb) ),
            MockRow( self.sheet, stingray.cell.NumberCell(2, self.wb),
              stingray.cell.TextCell("Second", self.wb), ),
            ]
    def test_should_iterate( self ):
        rows_as_dict_iter = (
            dict( zip( (a.name for a in self.sheet.schema), r ) )
            for r in self.sheet.rows() )
        row_list= list(  rows_as_dict_iter )
        self.assertEqual( 'The_Name', self.wb.requested )
        self.assertEqual( 2, len(row_list) )
        self.assertTrue( all( isinstance(r,dict) for r in row_list ) )
        row= row_list[0]
        self.assertEqual( 1, row['Col 1'].to_int() )
        self.assertEqual( "First", row['Col 2'].to_str() )
        row= row_list[1]
        self.assertEqual( 2, row['Col 1'].to_int() )
        self.assertEqual( "Second", row['Col 2'].to_str() )
    def test_should_have_attributes( self ):
        self.assertEqual( 'The_Name', self.sheet.name )

14.5.5. EmbeddedSchemaSheet Tests

An sheet.EmbeddedSchemaSheet creates a schema from the workbook and produces rows. It relies on a schema.loader.HeadingRowSchemaLoader, which we must mock.

Here’s a mock schema loader.

class MockLoader:
    def __init__( self, sheet ):
        self.sheet= sheet
    def schema( self ):
        schema= stingray.schema.Schema(
            stingray.schema.Attribute( "Col 1" ),
            stingray.schema.Attribute( "Col 2" )
            )
        return schema
    def rows( self ):
        row_iter= iter( self.sheet.rows() )
        skip_this= next(row_iter)
        return row_iter
class TestEmbeddedSchemaSheet( unittest.TestCase ):
    def setUp( self ):
        self.wb= SheetMockWorkbook( )
        self.sheet= stingray.sheet.EmbeddedSchemaSheet( self.wb, 'The_Name', loader_class=MockLoader )
        self.wb.rows = [
            MockRow( self.sheet, stingray.cell.TextCell("Col 1", self.wb),
              stingray.cell.TextCell("Col 2", self.wb) ),
            MockRow( self.sheet, stingray.cell.NumberCell(1, self.wb),
              stingray.cell.TextCell("First", self.wb) ),
            MockRow( self.sheet, stingray.cell.NumberCell(2, self.wb),
              stingray.cell.TextCell("Second", self.wb), ),
            ]
    def test_should_iterate( self ):
        rows_as_dict_iter = (
            dict( zip( (a.name for a in self.sheet.schema), r ) )
            for r in self.sheet.rows() )
        row_list= list(  rows_as_dict_iter )
        self.assertEqual( 'The_Name', self.wb.requested )
        self.assertEqual( 2, len(row_list) )
        self.assertTrue( all( isinstance(r,dict) for r in row_list ) )
        row= row_list[0]
        self.assertEqual( 1, row['Col 1'].to_int() )
        self.assertEqual( "First", row['Col 2'].to_str() )
        row= row_list[1]
        self.assertEqual( 2, row['Col 1'].to_int() )
        self.assertEqual( "Second", row['Col 2'].to_str() )
    def test_should_have_attributes( self ):
        self.assertEqual( 'The_Name', self.sheet.name )

14.5.6. Test Suite and Runner

In case we want to build up a larger test suite, we avoid doing any real work unless this is the main module being executed.

import test
suite= test.suite_maker( globals() )

if __name__ == "__main__":
    print( __file__ )
    unittest.TextTestRunner().run(suite())