import os
import fnmatch
import re
import winreg
import subprocess
import sys
import itertools
import collections
import argparse
import msvcrt
import random
import unittest
import unittest.mock as mock
import build
from xml.etree import ElementTree
_SAMPLE_PROJECT = rb"""
Library
Azimuth
v4.8
..\..\..\
$(SourceRoot)\Bin\$(Configuration)\
$(SourceRoot)\Junk\$(AssemblyName)\$(Configuration)\
3.5
3.5
3.5
False
..\..\..\Bin\Release\UnitTestSharp.dll
False
..\..\..\Bin\Release\Reffed.dll
..\..\..\3rdParty\High-Speed-Priority-Queue-for-C-Sharp\3rdParty1.dll
..\..\..\3rdParty\Dir1\Dir2\Dir3\3rdParty2.dll
Test
Test2
call "$(SolutionDir)..\..\Bin\Release\prebuild_dependency.exe"
call "$(SolutionDir)..\..\Bin\Release\postbuild_dependency.exe"
"""
_SAMPLE_SLN = r"""
Project("") = "sample", "sample.csproj", ""
EndProject
"""
_DEPS_SLN = r"""
Project("") = "dependency1", "/testDir/dependency1.csproj", ""
EndProject
Project("") = "dependency2", "/testDir/dependency2.csproj", ""
EndProject
Project("") = "dependency3", "/testDir/dependency3.csproj", ""
EndProject
Project("") = "dependency4", "/testDir/dependency4.csproj", ""
EndProject
"""
_TEST_SLN = r"""
Project("") = "test", "/testDir/test.csproj", ""
EndProject
Project("") = "dependency1", "/testDir/dependency1.csproj", ""
EndProject
"""
class BuildTests(unittest.TestCase):
def setUp(self):
pass
@mock.patch('os.walk')
def test_recursive_glob(self, mock_walk):
mock_files = ['file1.py', 'file2.csproj', 'file3.sln', 'dir/file4.csproj']
mock_walk.return_value = (('/some_path', None, mock_files),)
files = build.recursive_glob('/some_path', '*.csproj')
expected = [('/some_path', 'file2.csproj'), ('/some_path', 'dir/file4.csproj')]
self.assertSetEqual(set(expected), set(files))
def test_extract_third_party(self):
xml = ElementTree.fromstring(_SAMPLE_PROJECT)
dependencies = build.extract_third_party(xml)
self.assertSetEqual(
set(['3rdParty1', '3rdParty2']),
set(dependencies))
def test_extract_third_party_empty(self):
xml = ElementTree.fromstring("")
dependencies = build.extract_third_party(xml)
self.assertSetEqual(set([]), set(dependencies))
def test_extract_itemgroup_references(self):
xml = ElementTree.fromstring(_SAMPLE_PROJECT)
dependencies = build.extract_itemgroup_references(xml)
self.assertSetEqual(
set(['UnitTestSharp', 'Reffed', 'Test', 'Test2']),
set(dependencies))
def test_extract_itemgroup_references_empty(self):
xml = ElementTree.fromstring("")
dependencies = build.extract_itemgroup_references(xml)
self.assertSetEqual(set(), set(dependencies))
def test_extract_build_events_dependencies(self):
xml = ElementTree.fromstring(_SAMPLE_PROJECT)
dependencies = build.extract_build_events_dependencies(xml)
self.assertSetEqual(
set(['prebuild_dependency', 'postbuild_dependency']),
set(dependencies))
def test_extract_build_events_dependencies_empty(self):
xml = ElementTree.fromstring("")
dependencies = build.extract_build_events_dependencies(xml)
self.assertSetEqual(set([]), set(dependencies))
def test_extract_dependencies(self):
xml = ElementTree.fromstring(_SAMPLE_PROJECT)
dependencies = build.extract_dependencies(xml)
self.assertSetEqual(
set(['UnitTestSharp',
'Reffed',
'Test',
'Test2',
'prebuild_dependency',
'postbuild_dependency']),
set(dependencies))
def test_extract_dependencies_empty(self):
xml = ElementTree.fromstring("")
dependencies = build.extract_dependencies(xml)
self.assertSetEqual(set([]), set(dependencies))
def test_find_visual_studio(self):
visual_studio = build.find_visual_studio('version')
self.assertIn('msbuild', visual_studio)
@mock.patch('builtins.open', new_callable=mock.mock_open)
@mock.patch('build.recursive_glob')
def test_find_projects(self, mock_glob, mock_open):
test_contents = {
os.path.join('test', 'sample.csproj'): _SAMPLE_PROJECT.decode(),
os.path.join('test', 'sample.sln'): _SAMPLE_SLN,
}
def faux_open(filename, mode):
return mock.mock_open(read_data=test_contents[filename]).return_value
mock_open.side_effect = faux_open
def faux_glob(path, filter):
if filter == '*.csproj':
return [('test', 'sample.csproj')]
else:
return [('test', 'sample.sln')]
mock_glob.side_effect = faux_glob
projects = build.find_projects('base')
self.assertEqual(1, len(projects))
self.assertSequenceEqual(['Azimuth'], list(projects.keys()))
self.assertEqual('Azimuth', projects['Azimuth'].name)
self.assertEqual('sample.csproj', projects['Azimuth'].filename)
self.assertEqual('test\sample.csproj', projects['Azimuth'].csproj_path)
self.assertEqual(['UnitTestSharp', 'Reffed', 'Test', 'Test2'], projects['Azimuth'].dependencies)
self.assertEqual(['prebuild_dependency', 'postbuild_dependency'], projects['Azimuth'].tools)
self.assertEqual(['3rdParty1', '3rdParty2'], projects['Azimuth'].third_party)
self.assertEqual(['test/sample.sln'], projects['Azimuth'].solutions)
self.assertEqual([], projects['Azimuth'].issues)
self.assertEqual('UNKNOWN', projects['Azimuth'].status)
self.assertEqual('Azimuth.dll', projects['Azimuth'].binary_name)
self.assertTrue(projects['Azimuth'].is_library)
class ProjectTests(unittest.TestCase):
def setUp(self):
self.project = build.Project('test', '/testDir', 'test.csproj')
self.project.dependencies = ['dependency1', 'dependency2', 'dependency3', 'dependency4']
self.project.third_party = ['1', '2', '3']
self.projects = [self.project,
build.Project('dependency1', '/testDir', 'dependency1.csproj'),
build.Project('dependency2', '/testDir', 'dependency2.csproj'),
build.Project('dependency3', '/testDir', 'dependency3.csproj'),
build.Project('dependency4', '/testDir', 'dependency4.csproj'),
build.Project('neverIncluded', '/testDir', 'neverIncluded.csproj')]
self.projects = collections.OrderedDict([(project.name, project)
for project in self.projects])
self.projects['dependency2'].tools = ['dependency3']
self.projects['dependency3'].dependencies = ['dependency4']
self.projects['dependency1'].third_party = ['1', '2', '4']
self.projects['dependency2'].third_party = ['1', '2', '5']
self.projects['dependency3'].third_party = ['1', '2', '6']
self.projects['dependency4'].third_party = ['1', '2', '7']
def test_recursive_dependencies(self):
dependencies = list(self.project.recursive_dependencies(self.projects))
expected = set(self.projects.values())
expected.remove(self.projects['neverIncluded'])
self.assertSetEqual(expected, set(dependencies))
def test_recursive_dependencies_empty(self):
self.project.dependencies = []
dependencies = list(self.project.recursive_dependencies(self.projects))
self.assertSetEqual(set([self.project]), set(dependencies))
def test_recursive_dependencies_cycle(self):
self.projects['dependency1'].dependencies = ['test']
with self.assertRaisesRegex(RuntimeError, 'cycle'):
list(self.project.recursive_dependencies(self.projects))
def test_recursive_third_party(self):
third_party = list(self.project.recursive_third_party(self.projects))
self.assertSetEqual(set(['1', '2', '3', '4', '5', '6', '7']),
set(third_party))
def test_recursive_third_party_cycle(self):
self.projects['dependency1'].dependencies = ['test']
with self.assertRaisesRegex(RuntimeError, 'cycle'):
list(self.project.recursive_third_party(self.projects))
def test_recursively_find_third_party(self):
self.projects['test2'] = build.Project(
'dependency1', '/testDir', 'dependency1.csproj')
self.projects['test2'].third_party = ['T']
third_party = build.recursively_find_third_party(
self.projects, ['test', 'test2'])
self.assertSetEqual(set(['1', '2', '3', '4', '5', '6', '7', 'T']),
set(third_party))
def test_recursively_find_project_dependencies(self):
self.projects['dependency3'].dependencies = []
self.projects['test2'] = build.Project(
'dependency1', '/testDir', 'dependency1.csproj')
self.projects['test2'].dependencies = ['dependency4']
dependencies = build.recursively_find_project_dependencies(
self.projects, ['test', 'test2'])
expected = set(self.projects.values())
expected.remove(self.projects['neverIncluded'])
self.assertSetEqual(expected, set(dependencies))
def test_recursively_find_project_dependencies_cycle(self):
self.projects['dependency3'].dependencies = []
self.projects['test2'] = build.Project(
'dependency1', '/testDir', 'dependency1.csproj')
self.projects['test2'].dependencies = ['dependency4']
self.projects['dependency1'].dependencies = ['test']
with self.assertRaisesRegex(RuntimeError, 'cycle'):
build.recursively_find_project_dependencies(
self.projects, ['test', 'test2'])
def test_order_projects_by_build_order(self):
build_order = build.order_projects_by_build_order(self.projects)
build_order_names = [project.name for project in build_order]
expected_build_order = [
'dependency1',
'dependency4',
'dependency3',
'dependency2',
'neverIncluded',
'test']
self.assertSequenceEqual(expected_build_order, build_order_names)
def test_order_projects_by_build_order_subset_string(self):
build_order = build.order_projects_by_build_order(self.projects, 'test')
build_order_names = [project.name for project in build_order]
expected_build_order = [
'dependency1',
'dependency4',
'dependency3',
'dependency2',
'test']
self.assertSequenceEqual(expected_build_order, build_order_names)
def test_order_projects_by_build_order_subset_list(self):
build_order = build.order_projects_by_build_order(self.projects, ['dependency2', 'neverIncluded'])
build_order_names = [project.name for project in build_order]
expected_build_order = [
'dependency4',
'dependency3',
'dependency2',
'neverIncluded']
self.assertSequenceEqual(expected_build_order, build_order_names)
def test_order_projects_by_build_order_cycle(self):
self.projects['dependency1'].dependencies = ['test']
with self.assertRaisesRegex(RuntimeError, 'cycle'):
build.order_projects_by_build_order(self.projects)
def test_order_projects_by_build_order_subset_cycle_string(self):
self.projects['dependency1'].dependencies = ['test']
with self.assertRaisesRegex(RuntimeError, 'cycle'):
build.order_projects_by_build_order(self.projects, 'test')
def test_order_projects_by_build_order_subset_cycle_list(self):
self.projects['dependency1'].dependencies = ['test']
with self.assertRaisesRegex(RuntimeError, 'cycle'):
build.order_projects_by_build_order(self.projects, ['test', 'neverIncluded'])
@mock.patch('builtins.open', new_callable=mock.mock_open)
@mock.patch('build.recursive_glob')
def test_find_solutions_for_projects(self, mock_glob, mock_open):
test_contents = {
os.path.join('deps', 'deps.sln'): _DEPS_SLN,
os.path.join('test', 'never.sln'): "",
os.path.join('test', 'test.sln'): _TEST_SLN,
}
def fauxOpen(filename, mode):
return mock.mock_open(read_data=test_contents[filename]).return_value
mock_open.side_effect = fauxOpen
mock_glob.return_value=[('deps', 'deps.sln'),
('test', 'never.sln'),
('test', 'test.sln')]
build.find_solutions_for_projects(self.projects, 'test')
expected_dict = {
'dependency1': ['deps/deps.sln', 'test/test.sln'],
'dependency4': ['deps/deps.sln'],
'dependency3': ['deps/deps.sln'],
'dependency2': ['deps/deps.sln'],
'neverIncluded': [],
'test': ['test/test.sln'],
}
actual_dict = {project.name: project.solutions
for project in self.projects.values()}
self.assertDictEqual(expected_dict, actual_dict)
if __name__ == '__main__':
unittest.main()