blob: 5e77ca82b7eb0da72f0e0385b40c46eda98b7fc8 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* 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.
*/
package com.android.tools.metalava.cli.signature
import com.android.tools.metalava.cli.common.BaseOptionGroupTest
import com.android.tools.metalava.model.text.ApiParseException
import com.android.tools.metalava.model.text.FileFormat
import com.android.tools.metalava.testing.source
import com.github.ajalt.clikt.core.BadParameterValue
import com.google.common.truth.Truth.assertThat
import java.io.File
import kotlin.test.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Test
val SIGNATURE_FORMAT_OPTIONS_HELP =
"""
Signature Format Output:
Options controlling the format of the generated signature files.
See `metalava help signature-file-formats` for more information.
--api-overloaded-method-order [source|signature]
Specifies the order of overloaded methods in signature files. Applies to
the contents of the files specified on --api and --removed-api.
source - preserves the order in which overloaded methods appear in the
source files. This means that refactorings of the source files which change
the order but not the API can cause unnecessary changes in the API
signature files.
signature (default) - sorts overloaded methods by their signature. This
means that refactorings of the source files which change the order but not
the API will have no effect on the API signature files.
--format [v2|v3|v4|latest|recommended] Sets the output signature file format to be the given version.
v2 - The main version used in Android.
v3 - Adds support for using kotlin style syntax to embed nullability
information instead of using explicit and verbose @NonNull and @Nullable
annotations. This can be used for Java files and Kotlin files alike.
v4 - Adds support for using concise default values in parameters. Instead
of specifying the actual default values it just uses the `default` keyword.
latest - The latest in the supported versions. Only use this if you want to
have the very latest and are prepared to update signature files on a
continuous basis.
recommended (default) - The recommended version to use. This is currently
set to `v2` and will only change very infrequently so can be considered
stable.
--use-same-format-as <file> Specifies that the output format should be the same as the format used in
the specified file. It is an error if the file does not exist. If the file
is empty then this will behave as if it was not specified. If the file is
not a valid signature file then it will fail. Otherwise, the format read
from the file will be used.
If this is specified (and the file is not empty) then this will be used in
preference to most of the other options in this group. Those options will
be validated but otherwise ignored. The exception is the
--api-overloaded-method-order option which if present will be used.
The intention is that the other options will be used to specify the default
for new empty API files (e.g. created using `touch`) while this option is
used to specify the format for generating updates to the existing non-empty
files.
"""
.trimIndent()
class SignatureFormatOptionsTest :
BaseOptionGroupTest<SignatureFormatOptions>(
{ SignatureFormatOptions() },
SIGNATURE_FORMAT_OPTIONS_HELP
) {
@Test
fun `V1 not supported`() {
val e = assertThrows(BadParameterValue::class.java) { runTest("--format=v1") {} }
assertThat(e.message).startsWith("""Invalid value for "--format": invalid choice: v1.""")
}
@Test
fun `--use-same-format-as reads from a valid file and ignores --format`() {
val path = source("api.txt", "// Signature format: 3.0\n").createFile(temporaryFolder.root)
runTest("--use-same-format-as", path.path, "--format", "v4") {
assertThat(it.fileFormat).isEqualTo(FileFormat.V3)
}
}
@Test
fun `--use-same-format-as ignores empty file and falls back to format`() {
val path = source("api.txt", "").createFile(temporaryFolder.root)
runTest("--use-same-format-as", path.path, "--format", "v4") {
assertThat(it.fileFormat).isEqualTo(FileFormat.V4)
}
}
@Test
fun `--use-same-format-as will honor --api-overloaded-method-order=source`() {
val path = source("api.txt", "// Signature format: 2.0\n").createFile(temporaryFolder.root)
runTest("--use-same-format-as", path.path, "--api-overloaded-method-order=source") {
assertThat(it.fileFormat)
.isEqualTo(
FileFormat.V2.copy(
overloadedMethodOrder = FileFormat.OverloadedMethodOrder.SOURCE
)
)
}
}
@Test
fun `--use-same-format-as fails on non-existent file`() {
val e =
assertThrows(BadParameterValue::class.java) {
runTest("--use-same-format-as", "unknown.txt") {}
}
val path = File("unknown.txt").absolutePath
assertEquals("""Invalid value for "--use-same-format-as": $path is not a file""", e.message)
}
@Test
fun `--use-same-format-as fails to read from an invalid file`() {
val path =
source("api.txt", "// Not a signature file").createFile(temporaryFolder.root).path
val e =
assertThrows(ApiParseException::class.java) {
runTest("--use-same-format-as", path) {
// Get the file format as the file is only read when needed.
it.fileFormat
}
}
assertEquals(
"""Unknown file format of $path: invalid prefix, found '// Not a signature fi', expected '// Signature format: '""",
e.message
)
}
}