def test_get_unit_info(self, tmp_path): database = SqliteStateDatabase(tmp_path) test_unit = FortranWorkingState(database) test_unit.add_fortran_program_unit( FortranUnitID('foo', tmp_path / 'foo.f90')) test_unit.add_fortran_program_unit( FortranUnitID('bar', tmp_path / 'bar.F90')) test_unit.add_fortran_program_unit( FortranUnitID('bar', tmp_path / 'brb.f90')) test_unit.add_fortran_program_unit( FortranUnitID('baz', tmp_path / 'baz.f90')) test_unit.add_fortran_dependency( FortranUnitID('bar', tmp_path / 'brb.f90'), 'foo') test_unit.add_fortran_dependency( FortranUnitID('baz', tmp_path / 'baz.f90'), 'foo') test_unit.add_fortran_dependency( FortranUnitID('baz', tmp_path / 'baz.f90'), 'bar') assert test_unit.get_program_unit('foo') \ == [FortranInfo(FortranUnitID('foo', tmp_path/'foo.f90'))] assert test_unit.get_program_unit('bar') \ == [FortranInfo(FortranUnitID('bar', tmp_path/'bar.F90')), FortranInfo(FortranUnitID('bar', tmp_path/'brb.f90'), ['foo'])] assert test_unit.get_program_unit('baz') \ == [FortranInfo(FortranUnitID('baz', tmp_path/'baz.f90'), ['bar', 'foo'])]
def test_add_prerequisite(self): test_unit \ = FortranInfo(FortranUnitID('argle', Path('bargle/wargle.gargle'))) assert test_unit.depends_on == [] test_unit.add_prerequisite('cheese') assert test_unit.depends_on == ['cheese']
def test_default_constructor(self): test_unit \ = FortranInfo(FortranUnitID('argle', Path('bargle/wargle.gargle'))) assert test_unit.unit.name == 'argle' assert test_unit.unit.found_in == Path('bargle/wargle.gargle') assert test_unit.depends_on == []
def test_prereq_constructor(self): test_unit \ = FortranInfo(FortranUnitID('argle', Path('bargle/wargle.gargle')), ['cheese']) assert test_unit.unit.name == 'argle' assert test_unit.unit.found_in == Path('bargle/wargle.gargle') assert test_unit.depends_on == ['cheese']
def test_equality(self): test_unit \ = FortranInfo(FortranUnitID('argle', Path('bargle/wargle.gargle')), ['beef', 'cheese']) with pytest.raises(TypeError): _ = test_unit == 'not a FortranInfo' other = FortranInfo( FortranUnitID('argle', Path('bargle/wargle.gargle')), ['beef', 'cheese']) assert test_unit == other assert other == test_unit other = FortranInfo( FortranUnitID('argle', Path('bargle/wargle.gargle'))) assert test_unit != other assert other != test_unit
def test_harvested_data(self, caplog, tmp_path): """ Checks that the analyser deals with rescanning a file. """ caplog.set_level(logging.DEBUG) first_file: Path = tmp_path / 'other.F90' first_file.write_text( dedent(''' program betty use barney_mod, only :: dino implicit none end program betty module barney_mod end module barney_mod ''')) second_file: Path = tmp_path / 'test.f90' second_file.write_text( dedent(''' module barney_mod end module barney_mod ''')) database: SqliteStateDatabase = SqliteStateDatabase(tmp_path) test_unit = FortranAnalyser(tmp_path) first_artifact = Artifact(first_file, FortranSource, Raw) second_artifact = Artifact(second_file, FortranSource, Raw) # Not going to test returned objects this time _ = test_unit.run([first_artifact]) _ = test_unit.run([second_artifact]) # Confirm the database has been updated fdb = FortranWorkingState(database) assert list(iter(fdb)) \ == [FortranInfo(FortranUnitID('barney_mod', first_file)), FortranInfo(FortranUnitID('barney_mod', second_file)), FortranInfo(FortranUnitID('betty', first_file), ['barney_mod'])] assert list(fdb.depends_on(FortranUnitID('betty', first_file))) \ == [FortranUnitID('barney_mod', tmp_path / 'other.F90'), FortranUnitID('barney_mod', tmp_path / 'test.f90')] # Repeat the scan of second_file, there should be no change. # _ = test_unit.run([second_artifact]) fdb = FortranWorkingState(database) assert list(iter(fdb)) \ == [FortranInfo(FortranUnitID('barney_mod', first_file)), FortranInfo(FortranUnitID('barney_mod', second_file)), FortranInfo(FortranUnitID('betty', first_file), ['barney_mod'])] assert list(fdb.depends_on(FortranUnitID('betty', first_file))) \ == [FortranUnitID('barney_mod', tmp_path / 'other.F90'), FortranUnitID('barney_mod', tmp_path / 'test.f90')]
def test_get_program_unit(self, tmp_path: Path): database = SqliteStateDatabase(tmp_path) test_unit = FortranWorkingState(database) # Test on an empty list # with pytest.raises(WorkingStateException): _ = test_unit.get_program_unit('tigger') # Test we can retrieve an item from a single element list test_unit.add_fortran_program_unit( FortranUnitID('tigger', Path('tigger.f90'))) assert test_unit.get_program_unit('tigger') \ == [FortranInfo(FortranUnitID('tigger', Path('tigger.f90')))] with pytest.raises(WorkingStateException): _ = test_unit.get_program_unit('eeor') # Test retrieval from a multi-element list and with prerequisites. # test_unit.add_fortran_program_unit( FortranUnitID('eeor', Path('eeor.f90'))) test_unit.add_fortran_dependency( FortranUnitID('eeor', Path('eeor.f90')), 'pooh') test_unit.add_fortran_dependency( FortranUnitID('eeor', Path('eeor.f90')), 'piglet') assert test_unit.get_program_unit('tigger') \ == [FortranInfo(FortranUnitID('tigger', Path('tigger.f90')))] assert test_unit.get_program_unit('eeor') \ == [FortranInfo(FortranUnitID('eeor', Path('eeor.f90')), ['piglet', 'pooh'])] with pytest.raises(WorkingStateException): _ = test_unit.get_program_unit('pooh') # Test a multiply defined program unit. # test_unit.add_fortran_program_unit( FortranUnitID('tigger', Path('hundred.f90'))) assert test_unit.get_program_unit('tigger') \ == [FortranInfo(FortranUnitID('tigger', Path('hundred.f90'))), FortranInfo(FortranUnitID('tigger', Path('tigger.f90')))] assert test_unit.get_program_unit('eeor') \ == [FortranInfo(FortranUnitID('eeor', Path('eeor.f90')), ['piglet', 'pooh'])] with pytest.raises(WorkingStateException): _ = test_unit.get_program_unit('pooh')
def test_analyser_scope(self, caplog, tmp_path): """ Tests that the analyser is able to track scope correctly. """ caplog.set_level(logging.DEBUG) test_file: Path = tmp_path / 'test.f90' test_file.write_text( dedent(''' program fred implicit none if (something) then named: do i=1, 10 end do named endif contains subroutine yabadabadoo() end end program module barney implicit none type betty_type integer :: property contains procedure inspect end type interface betty_type procedure betty_constructor end contains function inspect(this) class(betty_type), intent(in) :: this integer :: inspect inspect = this%property end function inspect end module ''')) database: SqliteStateDatabase = SqliteStateDatabase(tmp_path) test_unit = FortranAnalyser(tmp_path) test_artifact = Artifact(test_file, FortranSource, Raw) output_artifacts = test_unit.run([test_artifact]) # Confirm database is updated working_state = FortranWorkingState(database) assert list(working_state) \ == [FortranInfo(FortranUnitID('barney', tmp_path/'test.f90'), []), FortranInfo(FortranUnitID('fred', tmp_path/'test.f90'), [])] # Confirm returned Artifact is updated assert len(output_artifacts) == 1 assert output_artifacts[0].defines == ['fred', 'barney'] assert output_artifacts[0].depends_on == [] assert output_artifacts[0].location == test_file assert output_artifacts[0].filetype is FortranSource assert output_artifacts[0].state is Analysed
def test_analyser_program_units(self, caplog, tmp_path): """ Tests that program units and the "uses" they contain are correctly identified. """ caplog.set_level(logging.DEBUG) test_file: Path = tmp_path / 'test.f90' test_file.write_text( dedent(''' program foo use iso_fortran_env, only : output use, intrinsic :: ios_c_binding use beef_mod implicit none end program foo module bar use iso_fortran_env, only : output use, intrinsic :: ios_c_binding use cheese_mod, only : bits_n_bobs implicit none end module bar function baz(first, second) use iso_fortran_env, only : output use, intrinsic :: ios_c_binding use teapot_mod implicit none end function baz subroutine qux() use iso_fortran_env, only : output use, intrinsic :: ios_c_binding use wibble_mod use wubble_mod, only: stuff_n_nonsense implicit none end subroutine qux ''')) database: SqliteStateDatabase = SqliteStateDatabase(tmp_path) test_unit = FortranAnalyser(tmp_path) test_artifact = Artifact(test_file, FortranSource, Raw) output_artifacts = test_unit.run([test_artifact]) # Confirm database is updated working_state = FortranWorkingState(database) assert list(working_state) \ == [FortranInfo(FortranUnitID('bar', tmp_path/'test.f90'), ['cheese_mod']), FortranInfo(FortranUnitID('baz', tmp_path/'test.f90'), ['teapot_mod']), FortranInfo(FortranUnitID('foo', tmp_path/'test.f90'), ['beef_mod']), FortranInfo(FortranUnitID('qux', tmp_path/'test.f90'), ['wibble_mod', 'wubble_mod'])] # Confirm returned Artifact is updated assert len(output_artifacts) == 1 assert output_artifacts[0].defines == ['foo', 'bar', 'baz', 'qux'] assert output_artifacts[0].depends_on == [ 'beef_mod', 'cheese_mod', 'teapot_mod', 'wibble_mod', 'wubble_mod' ] assert output_artifacts[0].location == test_file assert output_artifacts[0].filetype is FortranSource assert output_artifacts[0].state is Analysed
def test_add_remove_sequence(self, tmp_path: Path): database = SqliteStateDatabase(tmp_path) test_unit = FortranWorkingState(database) assert list(iter(test_unit)) == [] # Add a file containing a program unit and an unsatisfied dependency. # test_unit.add_fortran_program_unit( FortranUnitID('foo', Path('foo.f90'))) test_unit.add_fortran_dependency(FortranUnitID('foo', Path('foo.f90')), 'bar') assert list(iter(test_unit)) \ == [FortranInfo(FortranUnitID('foo', Path('foo.f90')), ['bar'])] assert list(test_unit.depends_on(FortranUnitID('foo', Path('foo.f90')))) \ == [FortranUnitUnresolvedID('bar')] # Add a second file containing a second program unit. # # This satisfies the previously dangling dependency and adds a new # one. # test_unit.add_fortran_program_unit( FortranUnitID('bar', Path('bar.F90'))) test_unit.add_fortran_dependency(FortranUnitID('bar', Path('bar.F90')), 'baz') assert list(iter(test_unit)) \ == [FortranInfo(FortranUnitID('bar', Path('bar.F90')), ['baz']), FortranInfo(FortranUnitID('foo', Path('foo.f90')), ['bar'])] assert list(test_unit.depends_on(FortranUnitID('foo', Path('foo.f90')))) \ == [FortranUnitID('bar', Path('bar.F90'))] assert list(test_unit.depends_on(FortranUnitID('bar', Path('bar.F90')))) \ == [FortranUnitUnresolvedID('baz')] # Add a third file also containing a third program unit and another # copy of the first. # # The new unit depends on two other units. # test_unit.add_fortran_program_unit( FortranUnitID('baz', Path('baz.F90'))) test_unit.add_fortran_program_unit( FortranUnitID('foo', Path('baz.F90'))) test_unit.add_fortran_dependency(FortranUnitID('baz', Path('baz.F90')), 'qux') test_unit.add_fortran_dependency(FortranUnitID('baz', Path('baz.F90')), 'cheese') assert list(iter(test_unit)) \ == [FortranInfo(FortranUnitID('bar', Path('bar.F90')), ['baz']), FortranInfo(FortranUnitID('baz', Path('baz.F90')), ['cheese', 'qux']), FortranInfo(FortranUnitID('foo', Path('baz.F90'))), FortranInfo(FortranUnitID('foo', Path('foo.f90')), ['bar'])] assert list(test_unit.depends_on(FortranUnitID('foo', Path('foo.f90')))) \ == [FortranUnitID('bar', Path('bar.F90'))] assert list(test_unit.depends_on(FortranUnitID('foo', Path('baz.F90')))) \ == [] assert list(test_unit.depends_on(FortranUnitID('bar', Path('bar.F90')))) \ == [FortranUnitID('baz', Path('baz.F90'))] assert list(test_unit.depends_on(FortranUnitID('baz', Path('baz.F90')))) \ == [FortranUnitUnresolvedID('qux'), FortranUnitUnresolvedID('cheese')] # Remove a previously added file # test_unit.remove_fortran_file(Path('baz.F90')) assert list(iter(test_unit)) \ == [FortranInfo(FortranUnitID('bar', Path('bar.F90')), ['baz']), FortranInfo(FortranUnitID('foo', Path('foo.f90')), ['bar'])] assert list(test_unit.depends_on(FortranUnitID('foo', Path('foo.f90')))) \ == [FortranUnitID('bar', Path('bar.F90'))] assert list(test_unit.depends_on(FortranUnitID('bar', Path('bar.F90')))) \ == [FortranUnitUnresolvedID('baz')]
def test_analyser_cbinding(self, caplog, tmp_path): """ Tests that C bind procedures are correctly detected. """ caplog.set_level(logging.DEBUG) test_file: Path = tmp_path / 'test.f90' test_file.write_text( dedent(''' module foo integer, bind(c), target, save :: quuz real, bind(c, name="corge"), target, save :: varname function bar() bind(c, name="bar_c") implicit none end function bar subroutine baz(), bind(c) implicit none end subroutine baz interface function qux() bind(c, name="qux_c") implicit none end function qux subroutine quux() bind(c) implicit none end subroutine quux end interface end module foo ''')) database: SqliteStateDatabase = SqliteStateDatabase(tmp_path) test_unit = FortranAnalyser(tmp_path) test_artifact = Artifact(test_file, FortranSource, Raw) output_artifacts = test_unit.run([test_artifact]) # Confirm database is updated # Fortran part working_state = FortranWorkingState(database) assert list(working_state) \ == [FortranInfo(FortranUnitID('foo', tmp_path/'test.f90'), ['quux', 'qux_c'])] # C part cworking_state = CWorkingState(database) assert list(cworking_state) \ == [CInfo(CSymbolID('bar_c', tmp_path/'test.f90'), []), CInfo(CSymbolID('baz', tmp_path/'test.f90'), []), CInfo(CSymbolID('corge', tmp_path/'test.f90'), []), CInfo(CSymbolID('quuz', tmp_path/'test.f90'), [])] # Confirm returned Artifact is updated assert len(output_artifacts) == 1 assert output_artifacts[0].defines \ == ['foo', 'quuz', 'corge', 'bar_c', 'baz'] assert output_artifacts[0].depends_on == ['qux_c', 'quux'] assert output_artifacts[0].location == test_file assert output_artifacts[0].filetype is FortranSource assert output_artifacts[0].state is Analysed