Рефакторинг. Парсинг csproj инструкций происходит с помощью трансляции управляемой разделителями
написаны тесты к парсерам
This commit is contained in:
parent
0e232871c4
commit
0cc17356c3
|
|
@ -0,0 +1,45 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import unittest
|
||||
from parser.CsprojParser.CsprojLineParser import CsprojLineParser
|
||||
|
||||
|
||||
class TestCsprojParser(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.parser = CsprojLineParser()
|
||||
|
||||
def test_parseAppStatement(self):
|
||||
statement = "app:SomeAppName"
|
||||
app_name = self.parser._CsprojLineParser__parseAppStatement(statement)
|
||||
|
||||
self.assertEqual(app_name, 'SomeAppName')
|
||||
|
||||
def test_parseKeyValueStatement(self):
|
||||
statement = r"key:myKey 'my value -bla bla'"
|
||||
setting = self.parser._CsprojLineParser__parseKeyValueStatement(statement)
|
||||
|
||||
self.assertEqual(setting.key, 'myKey')
|
||||
self.assertEqual(setting.value, 'my value -bla bla')
|
||||
|
||||
def test_parseAttributeStatement(self):
|
||||
statement = r"rel_path '../some_dir/some_file.txt'"
|
||||
setting = self.parser._CsprojLineParser__parseAttributeStatement(statement)
|
||||
|
||||
self.assertEqual(setting.attribute_name, 'rel_path')
|
||||
self.assertEqual(setting.attribute_value, r'../some_dir/some_file.txt')
|
||||
|
||||
def test_parse_keyedCsprojLine(self):
|
||||
statement = r"csproj app:coolApp key:CodesignKey 'iPhone Developer: Рустам Заитов (CTL85FZX6K)'"
|
||||
setting = self.parser.parse(statement)
|
||||
|
||||
self.assertEqual(setting.appName, 'coolApp')
|
||||
self.assertEqual(setting.key, 'CodesignKey')
|
||||
self.assertEqual(setting.value, 'iPhone Developer: Рустам Заитов (CTL85FZX6K)')
|
||||
|
||||
def test_parse_attributedCsprojLine(self):
|
||||
statement = r"csproj app:coolApp rel_path '../parent_dir/some_file.extension'"
|
||||
setting = self.parser.parse(statement)
|
||||
|
||||
self.assertEqual(setting.appName, 'coolApp')
|
||||
self.assertEqual(setting.attribute_name, 'rel_path')
|
||||
self.assertEqual(setting.attribute_value, '../parent_dir/some_file.extension')
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import unittest
|
||||
from parser.CsprojParser.CsprojParser import CsprojParser
|
||||
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.__lineCollection = [
|
||||
"csproj app:first key:key1 'value1'",
|
||||
"csproj app:first key:key2 'value2'",
|
||||
"csproj app:first attr1 'attr_val1'",
|
||||
"csproj app:first attr2 'attr_val2'",
|
||||
|
||||
"csproj app:second key:key1 'value1'",
|
||||
"csproj app:second key:key2 'value2'",
|
||||
"csproj app:second attr1 'attr_val1'",
|
||||
"csproj app:second attr2 'attr_val2'"]
|
||||
self.__parser = None
|
||||
|
||||
def __do_parse(self):
|
||||
self.__parser = CsprojParser(self.__lineCollection)
|
||||
self.__parser.parse()
|
||||
|
||||
def test_projectCount(self):
|
||||
self.__do_parse()
|
||||
|
||||
self.assertEqual(2, len(self.__parser.projects_dict))
|
||||
self.assertTrue('first' in self.__parser.projects_dict)
|
||||
self.assertTrue('second' in self.__parser.projects_dict)
|
||||
|
||||
def test_projectSettings(self):
|
||||
self.__do_parse()
|
||||
|
||||
first = self.__parser.projects_dict['first']
|
||||
second = self.__parser.projects_dict['second']
|
||||
|
||||
self.assertEqual(first.appName, 'first')
|
||||
self.assertEqual(second.appName, 'second')
|
||||
|
||||
setting_dict = {
|
||||
'key1': 'value1',
|
||||
'key2': 'value2'
|
||||
}
|
||||
self.assertDictEqual(first.settings, setting_dict)
|
||||
self.assertDictEqual(second.settings, setting_dict)
|
||||
|
||||
self.assertEqual(first.attr1, 'attr_val1')
|
||||
self.assertEqual(first.attr2, 'attr_val2')
|
||||
|
||||
self.assertEqual(second.attr1, 'attr_val1')
|
||||
self.assertEqual(second.attr2, 'attr_val2')
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
import unittest
|
||||
from parser.CsprojParser.CsprojParser import CsprojParser
|
||||
from parser.token import Token
|
||||
|
||||
|
||||
class TestCsprojParser(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = {'link': 'qwerty'}
|
||||
self.parser = CsprojParser(self.config)
|
||||
|
||||
|
||||
def test_isCsprojStatement(self):
|
||||
expect_true = self.parser.isCsprojStatement('csproj')
|
||||
expect_false = self.parser.isCsprojStatement('bla bla bla')
|
||||
|
||||
self.assertEqual(expect_true, True)
|
||||
self.assertEqual(expect_false, False)
|
||||
|
||||
def test_isAppToken(self):
|
||||
expect_true = self.parser.isAppStatement('app:TheCoolApp')
|
||||
expect_false = self.parser.isAppStatement('not_app:SomeIdentifier')
|
||||
|
||||
self.assertEqual(expect_true, True)
|
||||
self.assertEqual(expect_false, False)
|
||||
|
||||
def test_isKeyToken(self):
|
||||
expect_true = self.parser.isKeyStatement('key:MyKey')
|
||||
expect_false = self.parser.isKeyStatement('not_key:SomeIdentifier')
|
||||
|
||||
self.assertEqual(expect_true, True)
|
||||
self.assertEqual(expect_false, False)
|
||||
|
||||
def test_isAttributeToken(self):
|
||||
expect_true = self.parser.isAttributeToken('my_attrib_name')
|
||||
expect_false = self.parser.isKeyStatement('not_attrib:SomeIdentifier')
|
||||
|
||||
self.assertEqual(expect_true, True)
|
||||
self.assertEqual(expect_false, False)
|
||||
|
||||
def test_parseAppToken(self):
|
||||
token = self.parser.parseAppToken('app:MyCoolApp')
|
||||
self.assertEqual(token.content, 'MyCoolApp')
|
||||
|
||||
def test_parseKeyToken(self):
|
||||
token = self.parser.parseKeyToken('key:someValue')
|
||||
self.assertEqual(token.content, 'someValue')
|
||||
|
||||
def test_fetchValueFromValueToken(self):
|
||||
token = Token('@link', 'valueToken')
|
||||
value = self.parser.fetchValueFromValueToken(token)
|
||||
|
||||
self.assertEqual(value, 'qwerty')
|
||||
|
||||
def test_procCspojStatement(self):
|
||||
self.assertEqual(self.parser._token_index, 0)
|
||||
self.parser.procCspojStatement('csproj')
|
||||
self.assertEqual(self.parser._token_index, 1)
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import commands.build_command as bcmd
|
||||
import utils.csproj.patcher as csproj
|
||||
import parser.CsprojParser.CsprojParser as parser
|
||||
import parser.CsprojParser.CsprojLineParser as parser
|
||||
|
||||
class PatchCsproj(bcmd.BuildCommand):
|
||||
def __init__(self, config, path_provider):
|
||||
|
|
@ -16,7 +16,7 @@ class PatchCsproj(bcmd.BuildCommand):
|
|||
|
||||
|
||||
def FillPatchSettings(self, key_tokens):
|
||||
self._parser = parser.CsprojParser(self._config)
|
||||
self._parser = parser.CsprojLineParser(self._config)
|
||||
|
||||
for key_token in key_tokens:
|
||||
self._parser.parse(key_token, self._config[key_token])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
from parser.CsprojParser.CsprojSetting.AttribureSetting import AttributeSetting
|
||||
from parser.CsprojParser.CsprojSetting.KeyValueSetting import KeyValueSetting
|
||||
import re
|
||||
|
||||
class CsprojLineParser:
|
||||
def parse(self, line):
|
||||
ws = ' '
|
||||
csproj_regexp = "^(?P<cmd_name>csproj)"
|
||||
app_regexp = r"(?P<app>app:\S+)"
|
||||
setting_regexp = r"(?P<setting>\S+ '[^']+')$"
|
||||
|
||||
source = csproj_regexp + ws + app_regexp + ws + setting_regexp
|
||||
regexp = re.compile(source, re.UNICODE)
|
||||
|
||||
match = regexp.search(line)
|
||||
self.__guardMatch(match, line)
|
||||
|
||||
cmd_name = match.group('cmd_name')
|
||||
self.__parseCsprojStatement(cmd_name)
|
||||
|
||||
app_statement = match.group('app')
|
||||
appName = self.__parseAppStatement(app_statement)
|
||||
|
||||
setting_statement = match.group('setting')
|
||||
setting = self.__parseSettingStatement(setting_statement)
|
||||
|
||||
setting.appName = appName
|
||||
return setting
|
||||
|
||||
def __parseCsprojStatement(self, statement):
|
||||
pass
|
||||
|
||||
def __parseAppStatement(self, statement):
|
||||
patt = r'app:(?P<app_name>\w+)'
|
||||
|
||||
match = re.match(patt, statement)
|
||||
self.__guardMatch(match, statement)
|
||||
|
||||
return match.group('app_name')
|
||||
|
||||
def __parseSettingStatement(self, statement):
|
||||
self.__guardSource(statement)
|
||||
|
||||
if statement.startswith('key:'):
|
||||
result = self.__parseKeyValueStatement(statement)
|
||||
else:
|
||||
result = self.__parseAttributeStatement(statement)
|
||||
|
||||
return result
|
||||
|
||||
def __parseKeyValueStatement(self, statement):
|
||||
self.__guardSource(statement)
|
||||
patt = r"key:(?P<key>\w+) '(?P<value>[^']+)'"
|
||||
|
||||
match = re.search(patt, statement)
|
||||
self.__guardMatch(match, statement)
|
||||
|
||||
key = match.group('key')
|
||||
value = match.group('value')
|
||||
setting = KeyValueSetting(key, value)
|
||||
|
||||
return setting
|
||||
|
||||
def __parseAttributeStatement(self, statement):
|
||||
self.__guardSource(statement)
|
||||
patt = r"(?P<attribute_name>\w+) '(?P<attribute_value>[^']+)'"
|
||||
|
||||
match = re.search(patt, statement)
|
||||
self.__guardMatch(match, statement)
|
||||
|
||||
attribute_name = match.group('attribute_name')
|
||||
attribute_value = match.group('attribute_value')
|
||||
|
||||
setting = AttributeSetting(attribute_name, attribute_value)
|
||||
return setting
|
||||
|
||||
def __guardMatch(self, match_object, source):
|
||||
if match_object is None:
|
||||
msg = 'Recognition exception: {0}'.format(source)
|
||||
raise Exception(msg)
|
||||
|
||||
def __guardSource(self, source_text):
|
||||
assert source_text is not None and len(source_text) > 0
|
||||
|
|
@ -1,126 +1,34 @@
|
|||
from parser.CsprojParser.Csproj import Csproj
|
||||
from parser.StringValueParser import *
|
||||
from parser.AttributeNameParser import *
|
||||
from parser.token import Token
|
||||
from parser.CsprojParser.CsprojLineParser import CsprojLineParser
|
||||
|
||||
|
||||
class CsprojParser:
|
||||
def __init__(self, config):
|
||||
self._config = config
|
||||
self._statement_buffer = None
|
||||
self._token_index = 0
|
||||
self._current_project = None
|
||||
self._projects = {}
|
||||
def __init__(self, line_collection):
|
||||
assert line_collection is not None
|
||||
|
||||
def getProjects(self):
|
||||
return self._projects.values()
|
||||
self.line_collection = line_collection
|
||||
self.projects_dict = {}
|
||||
|
||||
def initStatementBuffer(self, string_to_parse, value_statement):
|
||||
self._statement_buffer = string_to_parse.split(' ')
|
||||
self._statement_buffer.append(value_statement)
|
||||
self._token_index = 0
|
||||
def parse(self):
|
||||
|
||||
def parse(self, string_to_parse, value_token):
|
||||
self.initStatementBuffer(string_to_parse, value_token)
|
||||
settings = []
|
||||
for line in self.line_collection:
|
||||
settings.append(self.__parse_line(line))
|
||||
|
||||
while self._token_index < len(self._statement_buffer):
|
||||
self.ProcessStatement()
|
||||
for s in settings:
|
||||
csproj = self.__fetchProject(s.appName)
|
||||
s.apply(csproj)
|
||||
|
||||
def __fetchProject(self, project_name):
|
||||
assert project_name is not None
|
||||
|
||||
def ProcessStatement(self):
|
||||
text = self.getCurrentStatement()
|
||||
csproj = self.projects_dict.get(project_name, Csproj(project_name))
|
||||
self.projects_dict[project_name] = csproj
|
||||
|
||||
if self.isCsprojStatement(text):
|
||||
self.procCspojStatement(text)
|
||||
return csproj
|
||||
|
||||
elif self.isAppStatement(text):
|
||||
self.procAppStatement(text)
|
||||
def __parse_line(self, line):
|
||||
line_parser = CsprojLineParser()
|
||||
setting = line_parser.parse(line)
|
||||
|
||||
elif self.isKeyStatement(text):
|
||||
self.procKeyStatement(text)
|
||||
|
||||
elif self.isAttributeToken(text):
|
||||
self.procAttributeToken(text)
|
||||
|
||||
else:
|
||||
raise Exception('unrecognized token', text)
|
||||
|
||||
def isCsprojStatement(self, text):
|
||||
return text == 'csproj'
|
||||
|
||||
def procCspojStatement(self, text):
|
||||
self._token_index += 1
|
||||
|
||||
def isAppStatement(self, token):
|
||||
return token.startswith('app:')
|
||||
|
||||
def procAppStatement(self, text):
|
||||
self.processAppToken(text)
|
||||
self._token_index += 1
|
||||
|
||||
def isKeyStatement(self, text):
|
||||
return text.startswith('key:')
|
||||
|
||||
def procKeyStatement(self, text):
|
||||
key_token = self.parseKeyToken(text)
|
||||
|
||||
self._token_index += 1
|
||||
text = self.getCurrentStatement()
|
||||
value_token = self.parseValueToken(text)
|
||||
value = self.fetchValueFromValueToken(value_token)
|
||||
|
||||
self._current_project.settings[key_token.content] = value
|
||||
self._token_index += 1
|
||||
|
||||
def isAttributeToken(self, token):
|
||||
return ':' not in token
|
||||
|
||||
def procAttributeToken(self, text):
|
||||
attribute_token = self.parseValueToken(text)
|
||||
|
||||
self._token_index += 1
|
||||
text = self.getCurrentStatement()
|
||||
value_token = self.parseValueToken(text)
|
||||
setattr(self._current_project, attribute_token.content, value_token.content)
|
||||
|
||||
self._token_index += 1
|
||||
|
||||
def parseAppToken(self, text):
|
||||
appName = text[len('app:'):]
|
||||
token = Token(appName, 'appToken')
|
||||
|
||||
return token
|
||||
|
||||
def processAppToken(self, text):
|
||||
appToken = self.parseAppToken(text)
|
||||
self.setCurrentProject(appToken.content)
|
||||
|
||||
def setCurrentProject(self, appName):
|
||||
exists = appName in self._projects
|
||||
|
||||
self._current_project = self._projects[appName] if exists else Csproj(appName)
|
||||
self._projects[appName] = self._current_project
|
||||
|
||||
def parseKeyToken(self, text):
|
||||
key_name = text[len('key:'):]
|
||||
token = Token(key_name, 'keyToken')
|
||||
|
||||
return token
|
||||
|
||||
def parseValueToken(self, text):
|
||||
token = Token(text, 'valueToken')
|
||||
|
||||
return token
|
||||
|
||||
def fetchValueFromValueToken(self, token):
|
||||
value = token.content
|
||||
|
||||
if value.startswith('@'):
|
||||
key = value[1:]
|
||||
value = self._config[key]
|
||||
|
||||
return value
|
||||
|
||||
def getCurrentStatement(self):
|
||||
token = self._statement_buffer[self._token_index]
|
||||
return token
|
||||
return setting
|
||||
|
|
@ -3,8 +3,13 @@ from parser.CsprojParser.CsprojSetting.CsprojSettingBase import CsprojSettingBas
|
|||
|
||||
class AttributeSetting(CsprojSettingBase):
|
||||
def __init__(self, name, value):
|
||||
self._notNoneOrEmpty(name)
|
||||
self._notNoneOrEmpty(value)
|
||||
|
||||
self.attribute_name = name
|
||||
self.attribute_value = value
|
||||
|
||||
def apply(self, csproj):
|
||||
assert csproj is not None
|
||||
|
||||
setattr(csproj, self.attribute_name, self.attribute_value)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
class CsprojSettingBase:
|
||||
def __init__(self):
|
||||
def __init__(self, appName=None):
|
||||
self.appName = appName
|
||||
pass
|
||||
|
||||
def apply(self, csproj):
|
||||
pass
|
||||
|
||||
def _notNoneOrEmpty(self, string_statement):
|
||||
assert string_statement is not None and len(string_statement) > 0
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ from parser.CsprojParser.CsprojSetting.CsprojSettingBase import CsprojSettingBas
|
|||
|
||||
class KeyValueSetting(CsprojSettingBase):
|
||||
def __init__(self, key, value):
|
||||
assert key is not None and key != ''
|
||||
assert value is not None and value != ''
|
||||
self._notNoneOrEmpty(key)
|
||||
self._notNoneOrEmpty(value)
|
||||
|
||||
self.key = key
|
||||
self.value = value
|
||||
|
|
|
|||
Loading…
Reference in New Issue