You've already forked v8-code-style
mirror of
https://github.com/1C-Company/v8-code-style.git
synced 2025-09-16 17:46:24 +02:00
committed by
GitHub
parent
067d2fdddc
commit
b1f73b74fa
@@ -49,6 +49,7 @@
|
||||
- Конструкция "Попытка...Исключение...КонецПопытки" не содержит кода в исключении
|
||||
- Аннотация для метода написана канонически
|
||||
- Используется аннотация &ИзменениеИКонтроль вместо &Вместо
|
||||
- НСтр формат строкового литерала
|
||||
- Использование булевного параметра обработчика события
|
||||
|
||||
|
||||
|
@@ -25,6 +25,7 @@ Import-Package: com._1c.g5.v8.bm.core;version="[7.0.0,8.0.0)",
|
||||
com._1c.g5.v8.dt.bsl.typesystem;version="[9.0.0,10.0.0)",
|
||||
com._1c.g5.v8.dt.bsl.typesystem.util;version="[9.0.0,10.0.0)",
|
||||
com._1c.g5.v8.dt.bsl.util;version="[7.0.0,8.0.0)",
|
||||
com._1c.g5.v8.dt.common;version="[6.0.0,7.0.0)",
|
||||
com._1c.g5.v8.dt.core.platform;version="[10.0.0,11.0.0)",
|
||||
com._1c.g5.v8.dt.lcore.util;version="[2.0.0,3.0.0)",
|
||||
com._1c.g5.v8.dt.mcore;version="[6.0.0,7.0.0)",
|
||||
|
@@ -0,0 +1,91 @@
|
||||
# NStr string literal format
|
||||
|
||||
## Noncompliant Code Example
|
||||
|
||||
Should pass only single string literal in first paramenter of the NStr function.
|
||||
|
||||
```bsl
|
||||
Procedure NonCompliant1(Message) Export
|
||||
|
||||
Message = NStr("en = 'User message'" + Chars.LF);
|
||||
|
||||
EndProcedure
|
||||
```
|
||||
|
||||
The string literal in first parameter should not be empty.
|
||||
|
||||
```bsl
|
||||
Procedure NonCompliant2(Message) Export
|
||||
|
||||
Message = NStr("");
|
||||
|
||||
EndProcedure
|
||||
```
|
||||
|
||||
The format of string literal should be valid: `"key1 = 'value 1'; key2 = 'value 2';"`.
|
||||
|
||||
```bsl
|
||||
Procedure NonCompliant3(Message) Export
|
||||
|
||||
Message = NStr("en = User message");
|
||||
|
||||
EndProcedure
|
||||
```
|
||||
|
||||
The language code should be existing language code in configuration languages.
|
||||
|
||||
```bsl
|
||||
Procedure NonCompliant4(Message) Export
|
||||
|
||||
Message = NStr("en2 = 'User message'");
|
||||
|
||||
EndProcedure
|
||||
```
|
||||
|
||||
The message for language code should not be empty.
|
||||
|
||||
```bsl
|
||||
Procedure NonCompliant5(Message) Export
|
||||
|
||||
Message = NStr("en = ''");
|
||||
|
||||
EndProcedure
|
||||
```
|
||||
|
||||
The message for language code should not ends with space.
|
||||
|
||||
```bsl
|
||||
Procedure NonCompliant6(Message) Export
|
||||
|
||||
Message = NStr("en = 'User message '");
|
||||
|
||||
EndProcedure
|
||||
```
|
||||
|
||||
The message for language code should not ends with new line.
|
||||
|
||||
```bsl
|
||||
Procedure NonCompliant7(Message) Export
|
||||
|
||||
Message = NStr("en = 'User message
|
||||
|'");
|
||||
|
||||
EndProcedure
|
||||
```
|
||||
|
||||
## Compliant Solution
|
||||
|
||||
|
||||
```bsl
|
||||
|
||||
Procedure Compliant(Message) Export
|
||||
|
||||
Message = NStr("en = 'User message'");
|
||||
|
||||
EndProcedure
|
||||
```
|
||||
|
||||
## See
|
||||
|
||||
- [About Nstr](https://1c-dn.com/1c_enterprise/nstr/)
|
||||
- [Interface texts in code: localization requirements](https://support.1ci.com/hc/en-us/articles/360011003480-Interface-texts-in-code-localization-requirements)
|
@@ -0,0 +1,90 @@
|
||||
# НСтр формат строкового литерала
|
||||
|
||||
## Неправильно
|
||||
|
||||
В первый параметр функции НСтр необходимо передавать только строковый литерал.
|
||||
|
||||
```bsl
|
||||
Процедура Неправильно1(Сообщение) Экспорт
|
||||
|
||||
Сообщение = НСтр("ru = 'Сообщение пользователю'" + Символы.ПС);
|
||||
|
||||
КонецПроцедуры
|
||||
```
|
||||
|
||||
Строковый литерал в первом параметре функции не должен быть пустым.
|
||||
|
||||
```bsl
|
||||
Процедура Неправильно2(Сообщение) Экспорт
|
||||
|
||||
Сообщение = НСтр("");
|
||||
|
||||
КонецПроцедуры
|
||||
```
|
||||
|
||||
Формат строкового литерала должен быть правильным: `"Ключ1 = 'значение 1'; Ключ2 = 'значение 2';"`.
|
||||
|
||||
```bsl
|
||||
Процедура Неправильно3(Сообщение) Экспорт
|
||||
|
||||
Сообщение = НСтр("ru = Сообщение пользователю");
|
||||
|
||||
КонецПроцедуры
|
||||
```
|
||||
|
||||
Должен использоваться существующий код языка из списка языков конфигурации.
|
||||
|
||||
```bsl
|
||||
Процедура Неправильно4(Сообщение) Экспорт
|
||||
|
||||
Сообщение = НСтр("ru2 = 'Сообщение пользователю'");
|
||||
|
||||
КонецПроцедуры
|
||||
```
|
||||
|
||||
Сообщение для кода языка не должно быть пустым.
|
||||
|
||||
```bsl
|
||||
Процедура Неправильно5(Сообщение) Экспорт
|
||||
|
||||
Сообщение = НСтр("ru = ''");
|
||||
|
||||
КонецПроцедуры
|
||||
```
|
||||
|
||||
Сообщение для кода языка не должно оканчиваться пробелом.
|
||||
|
||||
```bsl
|
||||
Процедура Неправильно6(Сообщение) Экспорт
|
||||
|
||||
Сообщение = НСтр("ru = 'Сообщение пользователю '");
|
||||
|
||||
КонецПроцедуры
|
||||
```
|
||||
|
||||
Сообщение для кода языка не должно оканчиваться новой строкой.
|
||||
|
||||
```bsl
|
||||
Процедура Неправильно7(Сообщение) Экспорт
|
||||
|
||||
Сообщение = НСтр("ru = 'Сообщение пользователю
|
||||
|'");
|
||||
|
||||
КонецПроцедуры
|
||||
```
|
||||
|
||||
## Правильно
|
||||
|
||||
|
||||
```bsl
|
||||
|
||||
Процедура Правильно(Сообщение) Экспорт
|
||||
|
||||
Сообщение = НСтр("ru = 'Сообщение пользователю'");
|
||||
|
||||
КонецПроцедуры
|
||||
```
|
||||
|
||||
## См.
|
||||
|
||||
[Интерфейсные тексты в коде: требования по локализации](https://its.1c.ru/db/v8std#contrut:761:hdoc)
|
@@ -46,6 +46,10 @@
|
||||
category="com.e1c.v8codestyle.bsl"
|
||||
class="com.e1c.v8codestyle.bsl.check.EmptyExceptStatementCheck">
|
||||
</check>
|
||||
<check
|
||||
category="com.e1c.v8codestyle.bsl"
|
||||
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.NstrStringLiteralFormatCheck">
|
||||
</check>
|
||||
<check
|
||||
category="com.e1c.v8codestyle.bsl"
|
||||
class="com.e1c.v8codestyle.internal.bsl.ExecutableExtensionFactory:com.e1c.v8codestyle.bsl.check.CanonicalPragmaCheck">
|
||||
|
@@ -67,6 +67,25 @@ final class Messages
|
||||
public static String StructureCtorTooManyKeysCheck_Structure_constructor_has_more_than__0__keys;
|
||||
public static String StructureCtorTooManyKeysCheck_title;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_Check_empty_interface_for_each_language;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_description;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_NStr_contains_unknown_language_code__S;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_NStr_format_is_incorrect__E;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_NStr_message_for_code__S__ends_with_space;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_NStr_message_for_language_code__S__is_empty;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_NStr_message_is_empty;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_NStr_method_should_accept_string_as_first_param;
|
||||
|
||||
public static String NstrStringLiteralFormatCheck_title;
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
// initialize resource bundle
|
||||
|
@@ -0,0 +1,183 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2021, 1C-Soft LLC and others.
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* 1C-Soft LLC - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.e1c.v8codestyle.bsl.check;
|
||||
|
||||
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.FEATURE_ACCESS__NAME;
|
||||
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.INVOCATION;
|
||||
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.STRING_LITERAL__LINES;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
import com._1c.g5.v8.dt.bsl.model.Expression;
|
||||
import com._1c.g5.v8.dt.bsl.model.Invocation;
|
||||
import com._1c.g5.v8.dt.bsl.model.StringLiteral;
|
||||
import com._1c.g5.v8.dt.bsl.model.util.BslUtil;
|
||||
import com._1c.g5.v8.dt.common.StringUtils;
|
||||
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
|
||||
import com._1c.g5.v8.dt.core.platform.V8ParametersStringParser;
|
||||
import com._1c.g5.v8.dt.metadata.mdclass.Language;
|
||||
import com.e1c.g5.v8.dt.check.CheckComplexity;
|
||||
import com.e1c.g5.v8.dt.check.ICheckParameters;
|
||||
import com.e1c.g5.v8.dt.check.components.BasicCheck;
|
||||
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
|
||||
import com.e1c.g5.v8.dt.check.settings.IssueType;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Checks {@link StringLiteral} format of NStr function that: <br>
|
||||
* 1. the literal content is not empty, <br>
|
||||
* 2. can be parsed with key-value without errors <br>
|
||||
* 3. each language code in the literal is known <br>
|
||||
* 4. message for each language code in literal is set and not empty<br>
|
||||
* 5. message is not ending on blank symbol<br>
|
||||
* 6. and optionally may check that each language of the project has translation <br>
|
||||
*
|
||||
* @author Dmitriy Marmyshev
|
||||
*/
|
||||
public class NstrStringLiteralFormatCheck
|
||||
extends BasicCheck
|
||||
{
|
||||
private static final String CHECK_ID = "bsl-nstr-string-literal-format"; //$NON-NLS-1$
|
||||
|
||||
private static final String PARAM_CHECK_EMPTY_INTERFACE = "checkEmptyInterface"; //$NON-NLS-1$
|
||||
|
||||
private static final String DEFAULT_CHECK_EMPTY_INTERFACE = Boolean.FALSE.toString();
|
||||
|
||||
private static final String NSTR_NAME = "NStr"; //$NON-NLS-1$
|
||||
|
||||
private static final String NSTR_NAME_RU = "НСтр"; //$NON-NLS-1$
|
||||
|
||||
private IV8ProjectManager v8ProjectManager;
|
||||
|
||||
/**
|
||||
* Instantiates a new NSTR string literal format check.
|
||||
*
|
||||
* @param v8ProjectManager the v 8 project manager service, cannot be {@code null}.
|
||||
*/
|
||||
@Inject
|
||||
public NstrStringLiteralFormatCheck(IV8ProjectManager v8ProjectManager)
|
||||
{
|
||||
super();
|
||||
this.v8ProjectManager = v8ProjectManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCheckId()
|
||||
{
|
||||
return CHECK_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureCheck(CheckConfigurer builder)
|
||||
{
|
||||
builder.title(Messages.NstrStringLiteralFormatCheck_title)
|
||||
.description(Messages.NstrStringLiteralFormatCheck_description)
|
||||
.complexity(CheckComplexity.NORMAL)
|
||||
.severity(IssueSeverity.MINOR)
|
||||
.issueType(IssueType.CODE_STYLE)
|
||||
.module()
|
||||
.checkedObjectType(INVOCATION)
|
||||
.parameter(PARAM_CHECK_EMPTY_INTERFACE, Boolean.class, DEFAULT_CHECK_EMPTY_INTERFACE,
|
||||
Messages.NstrStringLiteralFormatCheck_Check_empty_interface_for_each_language);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
|
||||
IProgressMonitor monitor)
|
||||
{
|
||||
Invocation inv = (Invocation)object;
|
||||
if (inv.getParams().isEmpty() || !(NSTR_NAME_RU.equalsIgnoreCase(inv.getMethodAccess().getName())
|
||||
|| NSTR_NAME.equalsIgnoreCase(inv.getMethodAccess().getName())))
|
||||
{
|
||||
return; // Not continue
|
||||
}
|
||||
|
||||
Expression first = inv.getParams().get(0);
|
||||
if (!(first instanceof StringLiteral))
|
||||
{
|
||||
resultAceptor.addIssue(
|
||||
Messages.NstrStringLiteralFormatCheck_NStr_method_should_accept_string_as_first_param,
|
||||
inv.getMethodAccess(), FEATURE_ACCESS__NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
final String fullString =
|
||||
String.join(System.lineSeparator(), BslUtil.getStringLiteralContent((StringLiteral)first, false));
|
||||
|
||||
if (StringUtils.isBlank(fullString))
|
||||
{
|
||||
resultAceptor.addIssue(Messages.NstrStringLiteralFormatCheck_NStr_message_is_empty, first,
|
||||
STRING_LITERAL__LINES);
|
||||
return;
|
||||
}
|
||||
|
||||
V8ParametersStringParser parser = new V8ParametersStringParser(fullString);
|
||||
if (!parser.getStatus().isOK())
|
||||
{
|
||||
String message = MessageFormat.format(Messages.NstrStringLiteralFormatCheck_NStr_format_is_incorrect__E,
|
||||
parser.getStatus().getMessage());
|
||||
resultAceptor.addIssue(message, first, STRING_LITERAL__LINES);
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<String> codes = v8ProjectManager.getProject(inv)
|
||||
.getLanguages()
|
||||
.stream()
|
||||
.map(Language::getLanguageCode)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final Map<String, String> params = parser.getParameters();
|
||||
for (Entry<String, String> entry : params.entrySet())
|
||||
{
|
||||
if (!codes.contains(entry.getKey()))
|
||||
{
|
||||
String message = MessageFormat.format(
|
||||
Messages.NstrStringLiteralFormatCheck_NStr_contains_unknown_language_code__S, entry.getKey());
|
||||
resultAceptor.addIssue(message, first, STRING_LITERAL__LINES);
|
||||
}
|
||||
else if (StringUtils.isBlank(entry.getValue()))
|
||||
{
|
||||
String message = MessageFormat.format(
|
||||
Messages.NstrStringLiteralFormatCheck_NStr_message_for_language_code__S__is_empty, entry.getKey());
|
||||
resultAceptor.addIssue(message, first, STRING_LITERAL__LINES);
|
||||
}
|
||||
else if (entry.getValue().endsWith(" ") || entry.getValue().endsWith(System.lineSeparator())) //$NON-NLS-1$
|
||||
{
|
||||
String message = MessageFormat.format(
|
||||
Messages.NstrStringLiteralFormatCheck_NStr_message_for_code__S__ends_with_space, entry.getKey());
|
||||
resultAceptor.addIssue(message, first, STRING_LITERAL__LINES);
|
||||
}
|
||||
}
|
||||
|
||||
boolean checkEmptyInterface = parameters.getBoolean(PARAM_CHECK_EMPTY_INTERFACE);
|
||||
if (inv.getParams().size() == 1 && checkEmptyInterface)
|
||||
{
|
||||
for (String code : codes)
|
||||
{
|
||||
if (!params.containsKey(code))
|
||||
{
|
||||
String message = MessageFormat.format(
|
||||
Messages.NstrStringLiteralFormatCheck_NStr_message_for_language_code__S__is_empty, code);
|
||||
resultAceptor.addIssue(message, first, STRING_LITERAL__LINES);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -49,6 +49,24 @@ EventHandlerBooleanParamCheck_Prams_to_set_to_False=Prams to set to False
|
||||
EventHandlerBooleanParamCheck_Prams_to_set_to_True=Prams to set to True
|
||||
EventHandlerBooleanParamCheck_title=Use event handler boolean parameter
|
||||
|
||||
NstrStringLiteralFormatCheck_Check_empty_interface_for_each_language = Check empty interface for each language
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_contains_unknown_language_code__S = NStr contains unknown language code {0}
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_format_is_incorrect__E = NStr format is incorrect {0}
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_message_for_code__S__ends_with_space = NStr message for code {0} ends with space
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_message_for_language_code__S__is_empty = NStr message for language code {0} is empty
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_message_is_empty = NStr message is empty
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_method_should_accept_string_as_first_param = NStr method should accept string as first param
|
||||
|
||||
NstrStringLiteralFormatCheck_description = NStr string literal format
|
||||
|
||||
NstrStringLiteralFormatCheck_title = NStr string literal format
|
||||
|
||||
QueryInLoop_Loop_has_method_with_query__0 = Loop has method with query "{0}"
|
||||
|
||||
QueryInLoop_Loop_has_query = Loop has query
|
||||
|
@@ -56,6 +56,24 @@ EventHandlerBooleanParamCheck_description = Использование буле
|
||||
|
||||
EventHandlerBooleanParamCheck_title = Использование булевного параметра обработчика события
|
||||
|
||||
NstrStringLiteralFormatCheck_Check_empty_interface_for_each_language = Проверять пустой интерфейс для каждого языка
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_contains_unknown_language_code__S = НСтр содержит неизвестный код языка {0}
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_format_is_incorrect__E = НСтр формат не корректен {0}
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_message_for_code__S__ends_with_space = НСтр сообщение для кода языка {0} оканчивается на пробел
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_message_for_language_code__S__is_empty = НСтр сообщение для кода языка {0} пустое
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_message_is_empty = НСтр сообщение пустое
|
||||
|
||||
NstrStringLiteralFormatCheck_NStr_method_should_accept_string_as_first_param = НСтр метод должен приниать строку первым параметром
|
||||
|
||||
NstrStringLiteralFormatCheck_description = НСтр формат строкового литерала
|
||||
|
||||
NstrStringLiteralFormatCheck_title = НСтр формат строкового литерала
|
||||
|
||||
QueryInLoop_Loop_has_method_with_query__0 = Цикл содержит вызов метода с запросом "{0}"
|
||||
|
||||
QueryInLoop_Loop_has_query = Цикл содержит выполнение запроса
|
||||
|
@@ -158,7 +158,7 @@ public class BslPlugin
|
||||
*
|
||||
* @return Guice injector of the plugin, never <code>null</code> if plugin is started
|
||||
*/
|
||||
/* package */ Injector getInjector()
|
||||
public Injector getInjector()
|
||||
{
|
||||
Injector localInstance = injector;
|
||||
if (localInstance == null)
|
||||
|
@@ -0,0 +1,7 @@
|
||||
|
||||
Procedure Compliant(Message) Export
|
||||
|
||||
Message = NStr("en = 'User message'");
|
||||
|
||||
EndProcedure
|
||||
|
@@ -0,0 +1,6 @@
|
||||
|
||||
Procedure NonCompliant1(Message) Export
|
||||
|
||||
Message = NStr("en = 'User message'" + Chars.LF);
|
||||
|
||||
EndProcedure
|
@@ -0,0 +1,6 @@
|
||||
|
||||
Procedure NonCompliant2(Message) Export
|
||||
|
||||
Message = NStr("");
|
||||
|
||||
EndProcedure
|
@@ -0,0 +1,6 @@
|
||||
|
||||
Procedure NonCompliant3(Message) Export
|
||||
|
||||
Message = NStr("en = User message");
|
||||
|
||||
EndProcedure
|
@@ -0,0 +1,6 @@
|
||||
|
||||
Procedure NonCompliant4(Message) Export
|
||||
|
||||
Message = NStr("en2 = 'User message'");
|
||||
|
||||
EndProcedure
|
@@ -0,0 +1,6 @@
|
||||
|
||||
Procedure NonCompliant5(Message) Export
|
||||
|
||||
Message = NStr("en = ''");
|
||||
|
||||
EndProcedure
|
@@ -0,0 +1,6 @@
|
||||
|
||||
Procedure NonCompliant6(Message) Export
|
||||
|
||||
Message = NStr("en = 'User message '");
|
||||
|
||||
EndProcedure
|
@@ -0,0 +1,7 @@
|
||||
|
||||
Procedure NonCompliant7(Message) Export
|
||||
|
||||
Message = NStr("en = 'User message
|
||||
|'");
|
||||
|
||||
EndProcedure
|
@@ -0,0 +1,235 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2021, 1C-Soft LLC and others.
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* 1C-Soft LLC - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.e1c.v8codestyle.bsl.check.itests;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.junit.Before;
|
||||
|
||||
import com._1c.g5.v8.bm.core.IBmObject;
|
||||
import com._1c.g5.v8.dt.bsl.model.Module;
|
||||
import com._1c.g5.v8.dt.core.platform.IDtProject;
|
||||
import com._1c.g5.v8.dt.metadata.mdclass.CommonModule;
|
||||
import com._1c.g5.v8.dt.validation.marker.Marker;
|
||||
import com.e1c.g5.v8.dt.check.ICheck;
|
||||
import com.e1c.g5.v8.dt.testing.check.CheckTestBase;
|
||||
import com.e1c.v8codestyle.internal.bsl.BslPlugin;
|
||||
|
||||
/**
|
||||
* Abstract test base which loads a project and updates its single module from a {@code test.bsl} resource if necessary.
|
||||
* Default project is {@code CommonModule} that allows to load rest resource to common module.
|
||||
*<br><br>
|
||||
* Clients may override the name of the project and path to the module, module id, and the way how to get the module
|
||||
* (for example manager module, object module, form module and etc).
|
||||
*
|
||||
* @author Dmitriy Marmyshev
|
||||
*/
|
||||
public class AbstractSingleModuleTestBase
|
||||
extends CheckTestBase
|
||||
{
|
||||
|
||||
private static final String PROJECT_NAME = "CommonModule";
|
||||
|
||||
private static final String FQN = "CommonModule.CommonModule";
|
||||
|
||||
private static final String COMMON_MODULE_FILE_NAME = "/src/CommonModules/CommonModule/Module.bsl";
|
||||
|
||||
private IDtProject dtProject;
|
||||
|
||||
private Class<? extends ICheck> checkClass;
|
||||
|
||||
private ICheck check;
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract single module test by the class of the check.
|
||||
*
|
||||
* @param checkClass the check class, cannot be {@code null}.
|
||||
*/
|
||||
protected AbstractSingleModuleTestBase(Class<? extends ICheck> checkClass)
|
||||
{
|
||||
super();
|
||||
this.checkClass = checkClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean enableCleanUp()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DT project instance.
|
||||
*
|
||||
* @return the project, cannot return {@code null}.
|
||||
*/
|
||||
protected IDtProject getProject()
|
||||
{
|
||||
return dtProject;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws CoreException {
|
||||
|
||||
IProject project = testingWorkspace.getProject(PROJECT_NAME);
|
||||
|
||||
if (!project.exists() || project.isAccessible())
|
||||
{
|
||||
testingWorkspace.cleanUpWorkspace();
|
||||
dtProject = openProjectAndWaitForValidationFinish(getTestConfigurationName());
|
||||
}
|
||||
dtProject = dtProjectManager.getDtProject(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the test configuration name, the project name.
|
||||
*
|
||||
* @return the test configuration name, cannot return {@code null}.
|
||||
*/
|
||||
protected String getTestConfigurationName()
|
||||
{
|
||||
return PROJECT_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module instance from the project.
|
||||
* <br><br>
|
||||
* Clients should override this method if they need to get module form different path
|
||||
* then {@code /ProjectName/src/CommonModules/CommonModule/Module.bsl}
|
||||
*
|
||||
* @return the module, cannot return {@code null}.
|
||||
*/
|
||||
protected Module getModule()
|
||||
{
|
||||
IBmObject mdObject = getTopObjectByFqn(FQN, dtProject);
|
||||
assertTrue(mdObject instanceof CommonModule);
|
||||
Module module = ((CommonModule)mdObject).getModule();
|
||||
assertNotNull(module);
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update project module file from bundle resource path, wait for validation and get the module.
|
||||
*
|
||||
* @param pathToResource the full path to resource in this bundle, cannot be {@code null}.
|
||||
* @return the module after validation, cannot return {@code null}.
|
||||
* @throws CoreException the core exception
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
protected Module updateAndGetModule(String pathToResource) throws CoreException, IOException
|
||||
{
|
||||
updateModule(pathToResource);
|
||||
|
||||
return getModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update project module file form bundle resource path and wait until validation finished.
|
||||
*
|
||||
* @param pathToResource the path to resource
|
||||
* @throws CoreException the core exception
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
protected void updateModule(String pathToResource) throws CoreException, IOException
|
||||
{
|
||||
try (InputStream in = getClass().getResourceAsStream(pathToResource))
|
||||
{
|
||||
IFile file = getProject().getWorkspaceProject().getFile(getModuleFileName());
|
||||
file.setContents(in, true, true, new NullProgressMonitor());
|
||||
}
|
||||
testingWorkspace.waitForBuildCompletion();
|
||||
waitForDD(getProject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module first marker for this check.
|
||||
*
|
||||
* @return the module first marker, may return {@code null} if there is no markers with the check ID.
|
||||
*/
|
||||
protected Marker getModuleFirstMarker()
|
||||
{
|
||||
return getFirstMarker(getCheckId(), getModuleId(), getProject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module project relative file path.
|
||||
*
|
||||
* @return the module file name, cannot return {@code null}.
|
||||
*/
|
||||
protected String getModuleFileName()
|
||||
{
|
||||
return COMMON_MODULE_FILE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module id it is full project resource path.
|
||||
*
|
||||
* @return the module id, cannot return {@code null}.
|
||||
*/
|
||||
protected String getModuleId()
|
||||
{
|
||||
return Path.ROOT.append(getTestConfigurationName()).append(getModuleFileName()).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module markers for this check.
|
||||
*
|
||||
* @return the module markers, cannot return {@code null}.
|
||||
*/
|
||||
protected List<Marker> getModuleMarkers()
|
||||
{
|
||||
List<Marker> markers = List.of(markerManager.getMarkers(getProject().getWorkspaceProject(), getModuleId()));
|
||||
|
||||
String chekcId = getCheckId();
|
||||
assertNotNull(chekcId);
|
||||
|
||||
return markers.stream()
|
||||
.filter(m -> chekcId.equals(getCheckIdFromMarker(m, getProject())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the check id gets from the check instance.
|
||||
*
|
||||
* @return the check id, cannot return {@code null}.
|
||||
*/
|
||||
protected String getCheckId()
|
||||
{
|
||||
return getCheckInstance().getCheckId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the check instance created in BSL bundle.
|
||||
*
|
||||
* @return the check instance, cannot return {@code null}.
|
||||
*/
|
||||
protected ICheck getCheckInstance()
|
||||
{
|
||||
if (check == null)
|
||||
{
|
||||
check = BslPlugin.getDefault().getInjector().getInstance(checkClass);
|
||||
}
|
||||
return check;
|
||||
}
|
||||
}
|
@@ -0,0 +1,167 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2021, 1C-Soft LLC and others.
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* 1C-Soft LLC - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.e1c.v8codestyle.bsl.check.itests;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com._1c.g5.v8.dt.validation.marker.Marker;
|
||||
import com.e1c.v8codestyle.bsl.check.NstrStringLiteralFormatCheck;
|
||||
|
||||
/**
|
||||
* Test for the {@link NstrStringLiteralFormatCheck} check.
|
||||
*
|
||||
* @author Dmitriy Marmyshev
|
||||
*/
|
||||
public class NstrStringLiteralFormatCheckTest
|
||||
extends AbstractSingleModuleTestBase
|
||||
{
|
||||
|
||||
private static final String FOLDER = "/resources/nstr-format/";
|
||||
|
||||
public NstrStringLiteralFormatCheckTest()
|
||||
{
|
||||
super(NstrStringLiteralFormatCheck.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Nstr first parameter is compliant
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Test
|
||||
public void testNstrStringLiteralCompliant() throws Exception
|
||||
{
|
||||
updateModule(FOLDER + "compliant.bsl");
|
||||
|
||||
Marker marker = getModuleFirstMarker();
|
||||
assertNull(marker);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that Nstr first parameter is string literal
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Test
|
||||
public void testNstrStringIsStringLiteral() throws Exception
|
||||
{
|
||||
updateModule(FOLDER + "non-compliant-1.bsl");
|
||||
|
||||
Marker marker = getModuleFirstMarker();
|
||||
assertNotNull(marker);
|
||||
assertEquals("4", marker.getExtraInfo().get("line"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Nstr first parameter is string literal and it is not empty
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Test
|
||||
public void testNstrStringLiteralIsEmpty() throws Exception
|
||||
{
|
||||
updateModule(FOLDER + "non-compliant-2.bsl");
|
||||
|
||||
Marker marker = getModuleFirstMarker();
|
||||
assertNotNull(marker);
|
||||
assertEquals("4", marker.getExtraInfo().get("line"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Nstr first parameter is string literal and it's format in valid key=value format
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Test
|
||||
public void testNstrStringLiteralFormatIsNotValid() throws Exception
|
||||
{
|
||||
updateModule(FOLDER + "non-compliant-3.bsl");
|
||||
|
||||
Marker marker = getModuleFirstMarker();
|
||||
assertNotNull(marker);
|
||||
assertEquals("4", marker.getExtraInfo().get("line"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Nstr first parameter is string literal contains not existing language code
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Test
|
||||
public void testNstrLanguageCodeNotExist() throws Exception
|
||||
{
|
||||
updateModule(FOLDER + "non-compliant-4.bsl");
|
||||
|
||||
Marker marker = getModuleFirstMarker();
|
||||
assertNotNull(marker);
|
||||
assertEquals("4", marker.getExtraInfo().get("line"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Nstr first parameter is string literal and the language text is empty
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Test
|
||||
public void testNstrLanguageTextIsEmpty() throws Exception
|
||||
{
|
||||
updateModule(FOLDER + "non-compliant-5.bsl");
|
||||
|
||||
Marker marker = getModuleFirstMarker();
|
||||
assertNotNull(marker);
|
||||
assertEquals("4", marker.getExtraInfo().get("line"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Nstr first parameter is string literal and language text ends with space.
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Test
|
||||
public void testNstrStringLiteralEndsWithStapce() throws Exception
|
||||
{
|
||||
updateModule(FOLDER + "non-compliant-6.bsl");
|
||||
|
||||
Marker marker = getModuleFirstMarker();
|
||||
assertNotNull(marker);
|
||||
assertEquals("4", marker.getExtraInfo().get("line"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Nstr first parameter is string literal and language text ends with new line.
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Test
|
||||
public void testNstrStringLiteralEndsWithNewLine() throws Exception
|
||||
{
|
||||
updateModule(FOLDER + "non-compliant-7.bsl");
|
||||
|
||||
Marker marker = getModuleFirstMarker();
|
||||
assertNotNull(marker);
|
||||
assertEquals("4", marker.getExtraInfo().get("line"));
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user