# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from robot.conf import Languages, LanguageLike, LanguagesLike
from robot.utils import normalize_whitespace
from .settings import (InitFileSettings, FileSettings, Settings, SuiteFileSettings,
ResourceFileSettings, TestCaseSettings, KeywordSettings)
from .tokens import StatementTokens, Token
[docs]
class LexingContext:
def __init__(self, settings: Settings, languages: Languages):
self.settings = settings
self.languages = languages
[docs]
def lex_setting(self, statement: StatementTokens):
self.settings.lex(statement)
[docs]
class FileContext(LexingContext):
settings: FileSettings
def __init__(self, lang: LanguagesLike = None):
languages = lang if isinstance(lang, Languages) else Languages(lang)
settings_class: 'type[FileSettings]' = type(self).__annotations__['settings']
settings = settings_class(languages)
super().__init__(settings, languages)
[docs]
def add_language(self, lang: LanguageLike):
self.languages.add_language(lang)
[docs]
def keyword_context(self) -> 'KeywordContext':
return KeywordContext(KeywordSettings(self.settings))
[docs]
def setting_section(self, statement: StatementTokens) -> bool:
return self._handles_section(statement, 'Settings')
[docs]
def variable_section(self, statement: StatementTokens) -> bool:
return self._handles_section(statement, 'Variables')
[docs]
def test_case_section(self, statement: StatementTokens) -> bool:
return False
[docs]
def task_section(self, statement: StatementTokens) -> bool:
return False
[docs]
def keyword_section(self, statement: StatementTokens) -> bool:
return self._handles_section(statement, 'Keywords')
[docs]
def lex_invalid_section(self, statement: StatementTokens):
header = statement[0]
header.type = Token.INVALID_HEADER
header.error = self._get_invalid_section_error(header.value)
for token in statement[1:]:
token.type = Token.COMMENT
def _get_invalid_section_error(self, header: str) -> str:
raise NotImplementedError
def _handles_section(self, statement: StatementTokens, header: str) -> bool:
marker = statement[0].value
if not marker or marker[0] != '*':
return False
normalized = self._normalize(marker)
if self.languages.headers.get(normalized) == header:
return True
if normalized == header[:-1]:
statement[0].error = (
f"Singular section headers like '{marker}' are deprecated. "
f"Use plural format like '*** {header} ***' instead."
)
return True
return False
def _normalize(self, marker: str) -> str:
return normalize_whitespace(marker).strip('* ').title()
[docs]
class SuiteFileContext(FileContext):
settings: SuiteFileSettings
[docs]
def test_case_context(self) -> 'TestCaseContext':
return TestCaseContext(TestCaseSettings(self.settings))
[docs]
def test_case_section(self, statement: StatementTokens) -> bool:
return self._handles_section(statement, 'Test Cases')
[docs]
def task_section(self, statement: StatementTokens) -> bool:
return self._handles_section(statement, 'Tasks')
def _get_invalid_section_error(self, header: str) -> str:
return (f"Unrecognized section header '{header}'. Valid sections: "
f"'Settings', 'Variables', 'Test Cases', 'Tasks', 'Keywords' "
f"and 'Comments'.")
[docs]
class ResourceFileContext(FileContext):
settings: ResourceFileSettings
def _get_invalid_section_error(self, header: str) -> str:
name = self._normalize(header)
if self.languages.headers.get(name) in ('Test Cases', 'Tasks'):
return f"Resource file with '{name}' section is invalid."
return (f"Unrecognized section header '{header}'. Valid sections: "
f"'Settings', 'Variables', 'Keywords' and 'Comments'.")
[docs]
class InitFileContext(FileContext):
settings: InitFileSettings
def _get_invalid_section_error(self, header: str) -> str:
name = self._normalize(header)
if self.languages.headers.get(name) in ('Test Cases', 'Tasks'):
return f"'{name}' section is not allowed in suite initialization file."
return (f"Unrecognized section header '{header}'. Valid sections: "
f"'Settings', 'Variables', 'Keywords' and 'Comments'.")
[docs]
class TestCaseContext(LexingContext):
settings: TestCaseSettings
def __init__(self, settings: TestCaseSettings):
super().__init__(settings, settings.languages)
@property
def template_set(self) -> bool:
return self.settings.template_set
[docs]
class KeywordContext(LexingContext):
settings: KeywordSettings
def __init__(self, settings: KeywordSettings):
super().__init__(settings, settings.languages)
@property
def template_set(self) -> bool:
return False