ты экспертный технический писатель. Напиши документацию по тексту "### Java

Для тестов используется фреймворк [JUnit](https://junit.org/junit5/) версий 4.x и 5.x.

Тестовый модуль для JUnit4 описывается модулем `JTEST()` или `JTEST_FOR(path/to/testing/module)`.
* `JTEST()`: система сборки будет искать тесты в `JAVA_SRCS()` данного модуля.
* `JTEST_FOR(path/to/testing/module)`: система сборки будет искать тесты в тестируемом модуле.

Для включения JUnit5 вместо `JTEST()` необходимо использовать `JUNIT5()`.

Содержание `bob.make` файла для `JUNIT5()` и `JTEST()` отличается только набором зависимостей.

Минимальный `bob.make` файл выглядит так:

{% list tabs %}

- JUnit4

  ```
  JTEST()

  JAVA_SRCS(FileTest.java)

  PEERDIR(
    # Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
    contrib/java/junit/junit/4.12 # Сам фреймворк JUnit 4
    contrib/java/org/hamcrest/hamcrest-all # Можно подключить набор Hamcrest матчеров
  )

  END()
  ```
- JUnit5
  ```
  JUNIT5()
  JAVE_SRCS(FileTest.java)
  PEERDIR(
    # Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
    contrib/java/org/junit/jupiter/junit-jupiter # Сам фреймворк JUnit 5
    contrib/java/org/hamcrest/hamcrest-all # Набор Hamcrest матчеров
  )
  END()
  ```

{% endlist %}

**Java classpath clashes**: Есть возможность включить автоматическую проверку на наличие нескольких одинаковых классов в [Java Classpath](https://en.wikipedia.org/wiki/Classpath). В проверке участвует не только имя класса, но и хэш-сумма файла с его исходным кодом, так как идентичные классы из разных библиотек проблем вызывать не должны. Для включения этого типа тестов в bob.make файл соответствующего проекта нужно добавить макрос `CHECK_JAVA_DEPS(yes)`.

**Linting**: На все исходные тексты на Java, которые подключены в секции `JAVA_SRCS`, включён статический анализ. Для проверки используется утилита [checkstyle](https://checkstyle.org/).

**Канонизация**: Для работы с канонизированными данными используйте функции из [devtools/jtest](https://a.bobndex-team.ru/arc/trunk/arcadia/devtools/jtest).

# Тесты на Java

Для Java [поддерживаются](https://docs.bobndex-team.ru/devtools/test/intro#framework) [JUnit](https://junit.org/) версий 4.х и 5.х.

## Тесты на JUnit 4 { #junit4 }

Запуск тестов на JUnit 4 описывается макросом `JTEST()`:

```bobmake
OWNER(g:my-group)

JTEST() # Используем JUnit 4

JAVA_SRCS(SRCDIR java **/*) # Где искать исходные коды тестов
JAVA_SRCS(SRCDIR resources **/*)

PEERDIR(
    # Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
    contrib/java/junit/junit/4.12 # Сам фреймворк Junit 4
    contrib/java/org/hamcrest/hamcrest-all # Можно подключить набор Hamcrest матчеров
)

JVM_ARGS( # Необязательный набор флагов, передаваемых JVM
    -Djava.net.preferIPv6Addresses=true
    -Djava.security.egd=file:///dev/urandom
    -Xms128m
    -Xmx256m
)

SYSTEM_PROPERTIES( # Необязательный набор значений, которые нужно положить в Java system properties. Эти значения переопределяют те, что были переданы в JVM_ARGS при помощи -D.
    key1 val1
    key2 val2
    FILE app.properties # Положить содержимое *.properties или *.xml файла
    FILE config.xml
)


END()
```

{% note info %}

Примеры продвинутой работы с Java system properties можно посмотреть [здесь](https://a.bobndex-team.ru/arc/trunk/arcadia/devtools/dummy_arcadia/test_java_properties). Поддерживаются различные `${name}` подстановки и загрузка данных из XML файлов.

{% endnote %}


Код тестов совершенно стандартный, например:

```java
package ru.bobndex.devtools.test;

import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class MathsTest {

    @Test
    public void testMultiply() {
        assertEquals(2 * 2, 4);
    }

}
```

## Тесты на JUnit 5 { #junit5 }

Запуск тестов на JUnit 5 отличается только набором зависимостей и используемым макросом `JUNIT5`:

```bobmake
OWNER(g:my-group)

JUNIT5() # Используем JUnit 5

JAVA_SRCS(SRCDIR java **/*)
JAVA_SRCS(SRCDIR resources **/*)

SIZE(MEDIUM)

INCLUDE(${ARCADIA_ROOT}/contrib/java/org/junit/junit-bom/5.7.1/bob.dependency_management.inc)
PEERDIR(
    # Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
    contrib/java/org/junit/jupiter/junit-jupiter # Сам фреймворк Junit 5
    contrib/java/org/hamcrest/hamcrest-all # Набор Hamcrest матчеров
)

END()
```

Пример теста:

```java
package ru.bobndex.devtools.test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;

class MathsTest {

    @Test
    void multiplication() {
        assertEquals(2 * 2, 4);
    }

}
```

## Доступ к зависимостям { #dependencies }

Если вы используете в своем **bob.make** [зависимости](https://docs.bobndex-team.ru/devtools/test/dependencies), то обращаться к таким данным в коде теста нужно, используя библиотеку [devtools/test/Paths](https://a.bobndex-team.ru/arcadia/devtools/jtest/src/main/java/ru/bobndex/devtools/test/Paths.java):

```java
package ru.bobndex.devtools.test;

import org.junit.jupiter.api.Test;
import ru.bobndex.devtools.test.Paths;

class ReadFileTest {

    @Test
    void read() {
        // Путь до файла/директории из репозитория, описанных с помощью макроса DATA("arcadia/devtools/dummy_arcadia/cat/main.cpp")
        String testFilePath = Paths.getSourcePath(
            "devtools/dummy_arcadia/cat/main.cpp"
        );

        // Путь до Sandbox-ресурса, описанного макросом DATA(sbr://53558626) # test.txt
        String sandboxResourcePath = Paths.getSandboxResourcesRoot() + "/test.txt";

        // Путь до файла из DEPENDS("devtools/dummy_arcadia/cat")
        // Обратите внимание: путь в DEPENDS указывает до сборочной цели, а BinaryPath требует указания пути до файла
        String binaryFilePath = Paths.getBuildPath(
            "devtools/dummy_arcadia/cat/cat"
        );

        // ...
    }

}
```

## Запуск JAVA_PROGRAM из теста

Если из теста есть необходимость запустить java-код, то можно воспользоваться следующим способом:
1. Добавить в `bob.make` теста конструкцию вида:
    ```
    PEERDIR(
        build/platform/java/jdk/jdk21
        ${JDK_RESOURCE_PEERDIR}
    )
    ```
2. Непосредственно в коде теста можно получить путь до JDK примерно так: 
    ```python
    import bobtest.common.runtime as runtime

    class DummyTest:
        def __init__(self, ...):
            self.jdkPath = runtime.global_resources()['JDK21_RESOURCE_GLOBAL']
    ```
    Конечно, вместо JDK21 здесь и в предыдущем пункте можно подставить JDK нужной версии.
3. Полученный путь перед запуском jar-ника нужно выставить в переменную окружения `JAVA_HOME`:
    ```python 
    os.environ["JAVA_HOME"] = self.jdkPath
    ```

## Директории доступные тесту

Помимо доступа к зависимостям бибилотека devtools/test/Paths позволяет узнать правильные пути до:
 * `getWorkPath()` - Возвращает путь до рабочей директории теста, где можно сохранять временные данные.
 * `getTestOutputsRoot()` - Возвращает путь до директории `testing_out_stuff`. Данные сохранённые внутри неё будут доступны после тестирования.
 * `getRamDrivePath()` - путь к RAM drive заказаному тестом через [REQUIREMENTS](https://docs.bobndex-team.ru/bob-make/manual/tests/common#requirements)
 * `getYtHddPath()` - путь к HDD диску доступному для записи временных данных для тестов запускаемых в [YT](https://docs.bobndex-team.ru/devtools/test/yt)

## Фильтрация по тегам { #filtering }

Тесты JUnit5 можно фильтровать по тегам. Например: 

```java
package ru.bobndex.devtools.test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;

class MathsTest {

    @Test
    @Tag("mult")
    void multiplication() {
        assertEquals(2 * 2, 4);
    }

    @Test
    @Tag("sum")
    void sum() {
        assertEquals(2 + 2, 4);
    }

}
```

Запустить только тест `multiplcation` возможно с помощью 
```
bob make -t --junit-args '--junit-tags mult'
```

## Доступ к параметрам { #parameters }

Для того, чтобы получить в коде значения [параметров](https://docs.bobndex-team.ru/devtools/test/manual#parameters):

```java
package ru.bobndex.devtools.test;

import org.junit.jupiter.api.Test;
import ru.bobndex.devtools.test.Params;

class ReadParametersTest {

    @Test
    void read() {
        // Значение параметра my-param
        String myParamValue = Params.params.get("my-param");

        // ...
    }

}
```

## Проверка classpath { #classpath-check }

Для тестов на Java возможно включить автоматическую проверку на наличие нескольких одинаковых классов в [Java Classpath](https://en.wikipedia.org/wiki/Classpath). В проверке участвует не только имя класса, но и хэш-сумма файла с его исходным кодом, так как идентичные классы из разных библиотек проблем вызывать не должны. Для включения этого типа тестов в bob.make файл соответствующего проекта нужно добавить макрос `CHECK_JAVA_DEPS(yes|no|strict)` [(docs)](/bob-make/manual/java/macros#check_java_deps):

```bobmake
OWNER(g:my-group)

JTEST()

JAVA_SRCS(SRCDIR java **/*)
JAVA_SRCS(SRCDIR resources **/*)

CHECK_JAVA_DEPS(yes) # Включаем проверку classpath

END()

```

## Статический анализ { #lint }

На все исходные тексты на Java, которые подключены в секции `JAVA_SRCS` файла **bob.make**, включён статический анализ. Для проверки используется утилита [checkstyle](https://checkstyle.org/). Поддерживается два уровня проверок: **обычный** и **расширенный** (extended). В расширенном режиме выполняется большее количество проверок. Есть возможность полностью отключить статический анализ.

```bobmake
OWNER(g:my-group)

JTEST()

JAVA_SRCS(SRCDIR java **/*)
JAVA_SRCS(SRCDIR resources **/*)

# Используйте один из следующих макросов:
LINT() # Включить статический анализатор
LINT(extended) # Включить статический анализатор в расширенном режиме (больше проверок)
NO_LINT() # Отключить статический анализатор

END()
```

{% note info %}

Конфигурационные файлы для статического анализа расположены [здесь](https://a.bobndex-team.ru/arc/trunk/arcadia/devtools/jstyle-runner/java/resources).

{% endnote %}

### To be documented

```
JTEST/JUNIT5
```
"