1 /* 2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.metalava.config 18 19 import com.android.tools.lint.checks.infrastructure.TestFile 20 import com.android.tools.metalava.testing.TemporaryFolderOwner 21 import com.google.common.truth.Truth.assertThat 22 import org.intellij.lang.annotations.Language 23 import org.junit.Rule 24 import org.junit.rules.TemporaryFolder 25 26 /** Base for tests for objects that are loaded from a configuration file. */ 27 open class BaseConfigParserTest : TemporaryFolderOwner { 28 @get:Rule override val temporaryFolder = TemporaryFolder() 29 30 /** Context for the tests. */ 31 data class TestContext( 32 /** The created [Config] being tested. */ 33 val config: Config, 34 ) 35 36 /** 37 * Run the test. 38 * 39 * @param configFiles The config files to parse. 40 * @param expectedFail The expected failure. 41 * @param body the body of the test which checks the state of the [Config] object which is made 42 * available as [TestContext.config]. 43 */ runTestnull44 protected fun runTest( 45 vararg configFiles: TestFile, 46 expectedFail: String = "", 47 body: (TestContext.() -> Unit)? = null, 48 ) { 49 val dir = temporaryFolder.newFolder() 50 val expectingFailure = expectedFail != "" 51 val hasBody = body != null 52 53 // If expecting a failure then it should not provide a body and if it is not expecting a 54 // failure then it must provide a body. 55 if (expectingFailure == hasBody) { 56 if (expectingFailure) error("Should not provide a body when expecting a failure") 57 else error("Must provide a body when not expecting a failure") 58 } 59 60 var errors = "" 61 try { 62 val files = configFiles.map { it.indented().createFile(dir) }.toList() 63 val config = ConfigParser.parse(files) 64 val context = TestContext(config = config) 65 if (body != null) context.body() 66 } catch (e: Exception) { 67 errors = cleanupString(e.message ?: "", project = dir) 68 } 69 assertThat(errors.trimIndent()).isEqualTo(expectedFail.trimIndent()) 70 } 71 72 /** 73 * Round trip [config], i.e. write it to XML, check it matches [xml], read it back in, check 74 * that it matches [config]. 75 * 76 * Writing configuration to XML is not something that Metalava needs at runtime, but it is 77 * useful to test what is written to a file as that is what can be read from the file. 78 */ roundTripnull79 protected fun roundTrip(config: Config, @Language("xml") xml: String) { 80 val configFile = temporaryFolder.newFile("round-trip-config.xml") 81 82 config.writeTo(configFile) 83 assertThat(configFile.readText().trimEnd()).isEqualTo(xml.trimIndent()) 84 85 val readConfig = ConfigParser.parse(listOf(configFile)) 86 assertThat(readConfig).isEqualTo(config) 87 } 88 } 89