1 /* 2 * Copyright (C) 2023 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.cli.common 18 19 import com.android.tools.metalava.ProgressTracker 20 import com.android.tools.metalava.testing.TemporaryFolderOwner 21 import com.github.ajalt.clikt.core.CliktCommand 22 import com.github.ajalt.clikt.core.context 23 import com.github.ajalt.clikt.core.subcommands 24 import com.github.ajalt.clikt.parameters.groups.OptionGroup 25 import com.github.ajalt.clikt.parameters.groups.provideDelegate 26 import org.junit.Assert 27 import org.junit.Rule 28 import org.junit.Test 29 import org.junit.rules.TemporaryFolder 30 31 /** Base class for tests of [OptionGroup] classes. */ 32 abstract class BaseOptionGroupTest<O : OptionGroup>( 33 private val expectedHelp: String, 34 ) : TemporaryFolderOwner { 35 36 @get:Rule override val temporaryFolder = TemporaryFolder() 37 createOptionsnull38 protected abstract fun createOptions(): O 39 40 /** 41 * Run a test on the [OptionGroup] of type [O]. 42 * 43 * Generally this will use the [OptionGroup] created by [createOptions] but that can be 44 * overridden for a test by providing an [optionGroup] parameter directly. 45 */ 46 protected fun runTest( 47 vararg args: String, 48 optionGroup: O? = null, 49 test: Result<O>.() -> Unit, 50 ) { 51 val testFactory = { optionGroup ?: createOptions() } 52 val command = MockCommand(testFactory) 53 val (executionEnvironment, stdout, stderr) = ExecutionEnvironment.forTest() 54 val rootCommand = MetalavaCommand(executionEnvironment, null, ProgressTracker()) 55 rootCommand.subcommands(command) 56 rootCommand.process(arrayOf("mock") + args) 57 val result = 58 Result( 59 options = command.options, 60 stdout = removeBoilerplate(stdout.toString()), 61 stderr = removeBoilerplate(stderr.toString()), 62 ) 63 result.test() 64 } 65 66 /** Remove various different forms of boilerplate text. */ removeBoilerplatenull67 private fun removeBoilerplate(out: String) = 68 out.trim() 69 .removePrefix("Aborting: ") 70 .removePrefix("Usage: metalava mock [options]") 71 .trim() 72 .removePrefix("Error: ") 73 74 data class Result<O : OptionGroup>( 75 val options: O, 76 val stdout: String, 77 val stderr: String, 78 ) 79 80 @Test 81 fun `Test help`() { 82 runTest { Assert.assertEquals(expectedHelp, stdout) } 83 } 84 } 85 86 private class MockCommand<O : OptionGroup>(factory: () -> O) : 87 CliktCommand(printHelpOnEmptyArgs = true) { 88 val options by factory() 89 90 init { <lambda>null91 context { 92 localization = MetalavaLocalization() 93 helpFormatter = MetalavaHelpFormatter(::plainTerminal, localization) 94 } 95 } 96 runnull97 override fun run() {} 98 } 99