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.systemui.statusbar.commandline
18 
19 import androidx.test.filters.SmallTest
20 import com.android.systemui.SysuiTestCase
21 import com.google.common.truth.Truth.assertThat
22 import java.io.PrintWriter
23 import org.junit.Assert.assertFalse
24 import org.junit.Assert.assertThrows
25 import org.junit.Assert.assertTrue
26 import org.junit.Test
27 
28 @SmallTest
29 class CommandParserTest : SysuiTestCase() {
30     private val parser = CommandParser()
31 
32     @Test
registerToken_cannotReuseNamesnull33     fun registerToken_cannotReuseNames() {
34         parser.flag("-f")
35         assertThrows(IllegalArgumentException::class.java) { parser.flag("-f") }
36     }
37 
38     @Test
unknownToken_throwsnull39     fun unknownToken_throws() {
40         assertThrows(ArgParseError::class.java) { parser.parse(listOf("unknown-token")) }
41     }
42 
43     @Test
parseSingleFlag_presentnull44     fun parseSingleFlag_present() {
45         val flag by parser.flag("-f")
46         parser.parse(listOf("-f"))
47         assertTrue(flag)
48     }
49 
50     @Test
parseSingleFlag_notPresentnull51     fun parseSingleFlag_notPresent() {
52         val flag by parser.flag("-f")
53         parser.parse(listOf())
54         assertFalse(flag)
55     }
56 
57     @Test
parseSingleOptionalParam_presentnull58     fun parseSingleOptionalParam_present() {
59         val param by parser.param("-p", valueParser = Type.Int)
60         parser.parse(listOf("-p", "123"))
61         assertThat(param).isEqualTo(123)
62     }
63 
64     @Test
parseSingleOptionalParam_notPresentnull65     fun parseSingleOptionalParam_notPresent() {
66         val param by parser.param("-p", valueParser = Type.Int)
67         parser.parse(listOf())
68         assertThat(param).isNull()
69     }
70 
71     @Test
parseSingleOptionalParam_missingArg_throwsnull72     fun parseSingleOptionalParam_missingArg_throws() {
73         val param by parser.param("-p", valueParser = Type.Int)
74         assertThrows(ArgParseError::class.java) { parser.parse(listOf("-p")) }
75     }
76 
77     @Test
parseSingleRequiredParam_presentnull78     fun parseSingleRequiredParam_present() {
79         val param by parser.require(parser.param("-p", valueParser = Type.Int))
80         parser.parse(listOf("-p", "123"))
81         assertThat(param).isEqualTo(123)
82     }
83 
84     @Test
parseSingleRequiredParam_notPresent_failsValidationnull85     fun parseSingleRequiredParam_notPresent_failsValidation() {
86         val param by parser.require(parser.param("-p", valueParser = Type.Int))
87         assertFalse(parser.parse(listOf()))
88     }
89 
90     @Test
parseSingleRequiredParam_missingArg_throwsnull91     fun parseSingleRequiredParam_missingArg_throws() {
92         val param by parser.require(parser.param("-p", valueParser = Type.Int))
93         assertThrows(ArgParseError::class.java) { parser.parse(listOf("-p")) }
94     }
95 
96     @Test
parseAsSubCommand_singleFlag_presentnull97     fun parseAsSubCommand_singleFlag_present() {
98         val flag by parser.flag("-f")
99         val args = listOf("-f").listIterator()
100         parser.parseAsSubCommand(args)
101 
102         assertTrue(flag)
103     }
104 
105     @Test
parseAsSubCommand_singleFlag_notPresentnull106     fun parseAsSubCommand_singleFlag_notPresent() {
107         val flag by parser.flag("-f")
108         val args = listOf("--other-flag").listIterator()
109         parser.parseAsSubCommand(args)
110 
111         assertFalse(flag)
112     }
113 
114     @Test
parseAsSubCommand_singleOptionalParam_presentnull115     fun parseAsSubCommand_singleOptionalParam_present() {
116         val param by parser.param("-p", valueParser = Type.Int)
117         parser.parseAsSubCommand(listOf("-p", "123", "--other-arg", "321").listIterator())
118         assertThat(param).isEqualTo(123)
119     }
120 
121     @Test
parseAsSubCommand_singleOptionalParam_notPresentnull122     fun parseAsSubCommand_singleOptionalParam_notPresent() {
123         val param by parser.param("-p", valueParser = Type.Int)
124         parser.parseAsSubCommand(listOf("--other-arg", "321").listIterator())
125         assertThat(param).isNull()
126     }
127 
128     @Test
parseAsSubCommand_singleRequiredParam_presentnull129     fun parseAsSubCommand_singleRequiredParam_present() {
130         val param by parser.require(parser.param("-p", valueParser = Type.Int))
131         parser.parseAsSubCommand(listOf("-p", "123", "--other-arg", "321").listIterator())
132         assertThat(param).isEqualTo(123)
133     }
134 
135     @Test
parseAsSubCommand_singleRequiredParam_notPresentnull136     fun parseAsSubCommand_singleRequiredParam_notPresent() {
137         parser.require(parser.param("-p", valueParser = Type.Int))
138         assertFalse(parser.parseAsSubCommand(listOf("--other-arg", "321").listIterator()))
139     }
140 
141     @Test
parseCommandWithSubCommand_required_providednull142     fun parseCommandWithSubCommand_required_provided() {
143         val topLevelFlag by parser.flag("flag", shortName = "-f")
144 
145         val cmd =
146             object : ParseableCommand("test") {
147                 val flag by flag("flag1")
148                 override fun execute(pw: PrintWriter) {}
149             }
150 
151         parser.require(parser.subCommand(cmd))
152         parser.parse(listOf("-f", "test", "--flag1"))
153 
154         assertTrue(topLevelFlag)
155         assertThat(cmd).isNotNull()
156         assertTrue(cmd.flag)
157     }
158 
159     @Test
parseCommandWithSubCommand_required_notProvidednull160     fun parseCommandWithSubCommand_required_notProvided() {
161         val topLevelFlag by parser.flag("-f")
162 
163         val cmd =
164             object : ParseableCommand("test") {
165                 val flag by parser.flag("flag1")
166                 override fun execute(pw: PrintWriter) {}
167             }
168 
169         parser.require(parser.subCommand(cmd))
170 
171         assertFalse(parser.parse(listOf("-f")))
172     }
173 
174     @Test
flag_requiredParam_optionalParam_allProvided_failsValidationnull175     fun flag_requiredParam_optionalParam_allProvided_failsValidation() {
176         val flag by parser.flag("-f")
177         val optionalParam by parser.param("-p", valueParser = Type.Int)
178         val requiredParam by parser.require(parser.param("-p2", valueParser = Type.Boolean))
179 
180         parser.parse(
181             listOf(
182                 "-f",
183                 "-p",
184                 "123",
185                 "-p2",
186                 "false",
187             )
188         )
189 
190         assertTrue(flag)
191         assertThat(optionalParam).isEqualTo(123)
192         assertFalse(requiredParam)
193     }
194 
195     @Test
flag_requiredParam_optionalParam_optionalExcludednull196     fun flag_requiredParam_optionalParam_optionalExcluded() {
197         val flag by parser.flag("-f")
198         val optionalParam by parser.param("-p", valueParser = Type.Int)
199         val requiredParam by parser.require(parser.param("-p2", valueParser = Type.Boolean))
200 
201         parser.parse(
202             listOf(
203                 "-p2",
204                 "true",
205             )
206         )
207 
208         assertFalse(flag)
209         assertThat(optionalParam).isNull()
210         assertTrue(requiredParam)
211     }
212 }
213