blob: 8fe82b6d0e2d261f9568d855919a1e4a6dec8438 [file] [log] [blame]
Mårten Kongstadbb520722023-04-26 13:16:41 +02001/*
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
17use anyhow::{anyhow, Context, Error, Result};
Mårten Kongstad416330b2023-05-05 11:10:01 +020018use protobuf::{Enum, EnumOrUnknown};
19use serde::{Deserialize, Serialize};
Mårten Kongstadbb520722023-04-26 13:16:41 +020020
Mårten Kongstad30950782023-05-09 13:31:29 +020021use crate::cache::{Cache, Item, Tracepoint};
Mårten Kongstad09c28d12023-05-04 13:29:26 +020022use crate::protos::{
Mårten Kongstad30950782023-05-09 13:31:29 +020023 ProtoFlagDefinition, ProtoFlagDefinitionValue, ProtoFlagOverride, ProtoFlagOverrides,
24 ProtoFlagPermission, ProtoFlagState, ProtoNamespace, ProtoParsedFlag, ProtoParsedFlags,
25 ProtoTracepoint,
Mårten Kongstad09c28d12023-05-04 13:29:26 +020026};
27
Mårten Kongstad416330b2023-05-05 11:10:01 +020028#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)]
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020029pub enum FlagState {
30 Enabled,
31 Disabled,
32}
33
34impl TryFrom<EnumOrUnknown<ProtoFlagState>> for FlagState {
35 type Error = Error;
36
37 fn try_from(proto: EnumOrUnknown<ProtoFlagState>) -> Result<Self, Self::Error> {
38 match ProtoFlagState::from_i32(proto.value()) {
39 Some(ProtoFlagState::ENABLED) => Ok(FlagState::Enabled),
40 Some(ProtoFlagState::DISABLED) => Ok(FlagState::Disabled),
41 None => Err(anyhow!("unknown flag state enum value {}", proto.value())),
42 }
43 }
44}
45
Mårten Kongstada1029092023-05-08 11:51:59 +020046impl From<FlagState> for ProtoFlagState {
47 fn from(state: FlagState) -> Self {
48 match state {
49 FlagState::Enabled => ProtoFlagState::ENABLED,
50 FlagState::Disabled => ProtoFlagState::DISABLED,
51 }
52 }
53}
54
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020055#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)]
Mårten Kongstad416330b2023-05-05 11:10:01 +020056pub enum Permission {
57 ReadOnly,
58 ReadWrite,
59}
60
Mårten Kongstad30950782023-05-09 13:31:29 +020061impl TryFrom<EnumOrUnknown<ProtoFlagPermission>> for Permission {
Mårten Kongstad416330b2023-05-05 11:10:01 +020062 type Error = Error;
63
Mårten Kongstad30950782023-05-09 13:31:29 +020064 fn try_from(proto: EnumOrUnknown<ProtoFlagPermission>) -> Result<Self, Self::Error> {
65 match ProtoFlagPermission::from_i32(proto.value()) {
66 Some(ProtoFlagPermission::READ_ONLY) => Ok(Permission::ReadOnly),
67 Some(ProtoFlagPermission::READ_WRITE) => Ok(Permission::ReadWrite),
Mårten Kongstad416330b2023-05-05 11:10:01 +020068 None => Err(anyhow!("unknown permission enum value {}", proto.value())),
69 }
70 }
71}
72
Mårten Kongstad30950782023-05-09 13:31:29 +020073impl From<Permission> for ProtoFlagPermission {
Mårten Kongstada1029092023-05-08 11:51:59 +020074 fn from(permission: Permission) -> Self {
75 match permission {
Mårten Kongstad30950782023-05-09 13:31:29 +020076 Permission::ReadOnly => ProtoFlagPermission::READ_ONLY,
77 Permission::ReadWrite => ProtoFlagPermission::READ_WRITE,
Mårten Kongstada1029092023-05-08 11:51:59 +020078 }
79 }
80}
81
Mårten Kongstad09c28d12023-05-04 13:29:26 +020082#[derive(Debug, PartialEq, Eq)]
83pub struct Value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020084 state: FlagState,
Mårten Kongstad416330b2023-05-05 11:10:01 +020085 permission: Permission,
Mårten Kongstad09c28d12023-05-04 13:29:26 +020086 since: Option<u32>,
87}
88
89#[allow(dead_code)] // only used in unit tests
90impl Value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020091 pub fn new(state: FlagState, permission: Permission, since: u32) -> Value {
92 Value { state, permission, since: Some(since) }
Mårten Kongstad09c28d12023-05-04 13:29:26 +020093 }
94
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020095 pub fn default(state: FlagState, permission: Permission) -> Value {
96 Value { state, permission, since: None }
Mårten Kongstad09c28d12023-05-04 13:29:26 +020097 }
98}
99
Mårten Kongstad30950782023-05-09 13:31:29 +0200100impl TryFrom<ProtoFlagDefinitionValue> for Value {
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200101 type Error = Error;
102
Mårten Kongstad30950782023-05-09 13:31:29 +0200103 fn try_from(proto: ProtoFlagDefinitionValue) -> Result<Self, Self::Error> {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200104 let Some(proto_state) = proto.state else {
105 return Err(anyhow!("missing 'state' field"));
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200106 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200107 let state = proto_state.try_into()?;
Mårten Kongstad416330b2023-05-05 11:10:01 +0200108 let Some(proto_permission) = proto.permission else {
109 return Err(anyhow!("missing 'permission' field"));
110 };
111 let permission = proto_permission.try_into()?;
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200112 Ok(Value { state, permission, since: proto.since })
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200113 }
114}
Mårten Kongstadbb520722023-04-26 13:16:41 +0200115
116#[derive(Debug, PartialEq, Eq)]
117pub struct Flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200118 pub name: String,
Mårten Kongstadbb520722023-04-26 13:16:41 +0200119 pub description: String,
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200120
121 // ordered by Value.since; guaranteed to contain at least one item (the default value, with
122 // since == None)
123 pub values: Vec<Value>,
Mårten Kongstadbb520722023-04-26 13:16:41 +0200124}
125
126impl Flag {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200127 #[allow(dead_code)] // only used in unit tests
Mårten Kongstadbb520722023-04-26 13:16:41 +0200128 pub fn try_from_text_proto(text_proto: &str) -> Result<Flag> {
Mårten Kongstad30950782023-05-09 13:31:29 +0200129 let proto: ProtoFlagDefinition = crate::protos::try_from_text_proto(text_proto)
Mårten Kongstadbb520722023-04-26 13:16:41 +0200130 .with_context(|| text_proto.to_owned())?;
131 proto.try_into()
132 }
133
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200134 pub fn resolve(&self, build_id: u32) -> (FlagState, Permission) {
135 let mut state = self.values[0].state;
Mårten Kongstad416330b2023-05-05 11:10:01 +0200136 let mut permission = self.values[0].permission;
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200137 for candidate in self.values.iter().skip(1) {
138 let since = candidate.since.expect("invariant: non-defaults values have Some(since)");
139 if since <= build_id {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200140 state = candidate.state;
Mårten Kongstad416330b2023-05-05 11:10:01 +0200141 permission = candidate.permission;
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200142 }
143 }
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200144 (state, permission)
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200145 }
Mårten Kongstadbb520722023-04-26 13:16:41 +0200146}
147
Mårten Kongstad30950782023-05-09 13:31:29 +0200148impl TryFrom<ProtoFlagDefinition> for Flag {
Mårten Kongstadbb520722023-04-26 13:16:41 +0200149 type Error = Error;
150
Mårten Kongstad30950782023-05-09 13:31:29 +0200151 fn try_from(proto: ProtoFlagDefinition) -> Result<Self, Self::Error> {
152 let Some(name) = proto.name else {
153 return Err(anyhow!("missing 'name' field"));
Mårten Kongstadbb520722023-04-26 13:16:41 +0200154 };
155 let Some(description) = proto.description else {
156 return Err(anyhow!("missing 'description' field"));
157 };
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200158 if proto.value.is_empty() {
Mårten Kongstadbb520722023-04-26 13:16:41 +0200159 return Err(anyhow!("missing 'value' field"));
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200160 }
161
162 let mut values: Vec<Value> = vec![];
163 for proto_value in proto.value.into_iter() {
164 let v: Value = proto_value.try_into()?;
165 if values.iter().any(|w| v.since == w.since) {
166 let msg = match v.since {
Mårten Kongstad30950782023-05-09 13:31:29 +0200167 None => format!("flag {}: multiple default values", name),
168 Some(x) => format!("flag {}: multiple values for since={}", name, x),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200169 };
170 return Err(anyhow!(msg));
171 }
172 values.push(v);
173 }
174 values.sort_by_key(|v| v.since);
175
Mårten Kongstad30950782023-05-09 13:31:29 +0200176 Ok(Flag { name, description, values })
177 }
178}
179
180#[derive(Debug, PartialEq, Eq)]
181pub struct Namespace {
182 pub namespace: String,
183 pub flags: Vec<Flag>,
184}
185
186impl Namespace {
187 pub fn try_from_text_proto(text_proto: &str) -> Result<Namespace> {
188 let proto: ProtoNamespace = crate::protos::try_from_text_proto(text_proto)
189 .with_context(|| text_proto.to_owned())?;
190 let Some(namespace) = proto.namespace else {
191 return Err(anyhow!("missing 'namespace' field"));
192 };
193 let mut flags = vec![];
194 for proto_flag in proto.flag.into_iter() {
195 flags.push(proto_flag.try_into()?);
196 }
197 Ok(Namespace { namespace, flags })
Mårten Kongstadbb520722023-04-26 13:16:41 +0200198 }
199}
200
201#[derive(Debug, PartialEq, Eq)]
202pub struct Override {
Mårten Kongstad30950782023-05-09 13:31:29 +0200203 pub namespace: String,
204 pub name: String,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200205 pub state: FlagState,
Mårten Kongstad416330b2023-05-05 11:10:01 +0200206 pub permission: Permission,
Mårten Kongstadbb520722023-04-26 13:16:41 +0200207}
208
209impl Override {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200210 #[allow(dead_code)] // only used in unit tests
Mårten Kongstadbb520722023-04-26 13:16:41 +0200211 pub fn try_from_text_proto(text_proto: &str) -> Result<Override> {
Mårten Kongstad30950782023-05-09 13:31:29 +0200212 let proto: ProtoFlagOverride = crate::protos::try_from_text_proto(text_proto)?;
Mårten Kongstadbb520722023-04-26 13:16:41 +0200213 proto.try_into()
214 }
215
216 pub fn try_from_text_proto_list(text_proto: &str) -> Result<Vec<Override>> {
Mårten Kongstad30950782023-05-09 13:31:29 +0200217 let proto: ProtoFlagOverrides = crate::protos::try_from_text_proto(text_proto)?;
218 proto.flag_override.into_iter().map(|proto_flag| proto_flag.try_into()).collect()
Mårten Kongstadbb520722023-04-26 13:16:41 +0200219 }
220}
221
Mårten Kongstad30950782023-05-09 13:31:29 +0200222impl TryFrom<ProtoFlagOverride> for Override {
Mårten Kongstadbb520722023-04-26 13:16:41 +0200223 type Error = Error;
224
Mårten Kongstad30950782023-05-09 13:31:29 +0200225 fn try_from(proto: ProtoFlagOverride) -> Result<Self, Self::Error> {
226 let Some(namespace) = proto.namespace else {
227 return Err(anyhow!("missing 'namespace' field"));
228 };
229 let Some(name) = proto.name else {
230 return Err(anyhow!("missing 'name' field"));
Mårten Kongstadbb520722023-04-26 13:16:41 +0200231 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200232 let Some(proto_state) = proto.state else {
233 return Err(anyhow!("missing 'state' field"));
Mårten Kongstadbb520722023-04-26 13:16:41 +0200234 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200235 let state = proto_state.try_into()?;
Mårten Kongstad416330b2023-05-05 11:10:01 +0200236 let Some(proto_permission) = proto.permission else {
237 return Err(anyhow!("missing 'permission' field"));
238 };
239 let permission = proto_permission.try_into()?;
Mårten Kongstad30950782023-05-09 13:31:29 +0200240 Ok(Override { namespace, name, state, permission })
Mårten Kongstadbb520722023-04-26 13:16:41 +0200241 }
242}
243
Mårten Kongstad30950782023-05-09 13:31:29 +0200244impl From<Cache> for ProtoParsedFlags {
Mårten Kongstada1029092023-05-08 11:51:59 +0200245 fn from(cache: Cache) -> Self {
Mårten Kongstad30950782023-05-09 13:31:29 +0200246 let mut proto = ProtoParsedFlags::new();
Mårten Kongstada1029092023-05-08 11:51:59 +0200247 for item in cache.into_iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200248 proto.parsed_flag.push(item.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200249 }
Mårten Kongstad30950782023-05-09 13:31:29 +0200250 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200251 }
252}
253
Mårten Kongstad30950782023-05-09 13:31:29 +0200254impl From<Item> for ProtoParsedFlag {
Mårten Kongstada1029092023-05-08 11:51:59 +0200255 fn from(item: Item) -> Self {
Mårten Kongstad30950782023-05-09 13:31:29 +0200256 let mut proto = crate::protos::ProtoParsedFlag::new();
257 proto.set_namespace(item.namespace.to_owned());
258 proto.set_name(item.name.clone());
259 proto.set_description(item.description.clone());
260 proto.set_state(item.state.into());
261 proto.set_permission(item.permission.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200262 for trace in item.trace.into_iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200263 proto.trace.push(trace.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200264 }
Mårten Kongstad30950782023-05-09 13:31:29 +0200265 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200266 }
267}
268
Mårten Kongstad30950782023-05-09 13:31:29 +0200269impl From<Tracepoint> for ProtoTracepoint {
270 fn from(tracepoint: Tracepoint) -> Self {
271 let mut proto = ProtoTracepoint::new();
272 proto.set_source(format!("{}", tracepoint.source));
273 proto.set_state(tracepoint.state.into());
274 proto.set_permission(tracepoint.permission.into());
275 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200276 }
277}
278
Mårten Kongstadbb520722023-04-26 13:16:41 +0200279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn test_flag_try_from_text_proto() {
285 let expected = Flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200286 name: "1234".to_owned(),
Mårten Kongstadbb520722023-04-26 13:16:41 +0200287 description: "Description of the flag".to_owned(),
Mårten Kongstad416330b2023-05-05 11:10:01 +0200288 values: vec![
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200289 Value::default(FlagState::Disabled, Permission::ReadOnly),
290 Value::new(FlagState::Enabled, Permission::ReadWrite, 8),
Mårten Kongstad416330b2023-05-05 11:10:01 +0200291 ],
Mårten Kongstadbb520722023-04-26 13:16:41 +0200292 };
293
294 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200295 name: "1234"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200296 description: "Description of the flag"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200297 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200298 state: DISABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200299 permission: READ_ONLY
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200300 }
301 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200302 state: ENABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200303 permission: READ_WRITE
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200304 since: 8
305 }
Mårten Kongstadbb520722023-04-26 13:16:41 +0200306 "#;
307 let actual = Flag::try_from_text_proto(s).unwrap();
308
309 assert_eq!(expected, actual);
310 }
311
312 #[test]
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200313 fn test_flag_try_from_text_proto_bad_input() {
314 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200315 name: "a"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200316 description: "Description of the flag"
317 "#;
318 let error = Flag::try_from_text_proto(s).unwrap_err();
319 assert_eq!(format!("{:?}", error), "missing 'value' field");
320
Mårten Kongstadbb520722023-04-26 13:16:41 +0200321 let s = r#"
322 description: "Description of the flag"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200323 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200324 state: ENABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200325 permission: READ_ONLY
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200326 }
Mårten Kongstadbb520722023-04-26 13:16:41 +0200327 "#;
328 let error = Flag::try_from_text_proto(s).unwrap_err();
329 assert!(format!("{:?}", error).contains("Message not initialized"));
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200330
331 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200332 name: "a"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200333 description: "Description of the flag"
334 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200335 state: ENABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200336 permission: READ_ONLY
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200337 }
338 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200339 state: ENABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200340 permission: READ_ONLY
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200341 }
342 "#;
343 let error = Flag::try_from_text_proto(s).unwrap_err();
344 assert_eq!(format!("{:?}", error), "flag a: multiple default values");
Mårten Kongstadbb520722023-04-26 13:16:41 +0200345 }
346
347 #[test]
Mårten Kongstad30950782023-05-09 13:31:29 +0200348 fn test_namespace_try_from_text_proto() {
349 let expected = Namespace {
350 namespace: "ns".to_owned(),
351 flags: vec![
352 Flag {
353 name: "a".to_owned(),
354 description: "A".to_owned(),
355 values: vec![Value::default(FlagState::Enabled, Permission::ReadOnly)],
356 },
357 Flag {
358 name: "b".to_owned(),
359 description: "B".to_owned(),
360 values: vec![Value::default(FlagState::Disabled, Permission::ReadWrite)],
361 },
362 ],
363 };
Mårten Kongstadbb520722023-04-26 13:16:41 +0200364
365 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200366 namespace: "ns"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200367 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200368 name: "a"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200369 description: "A"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200370 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200371 state: ENABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200372 permission: READ_ONLY
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200373 }
Mårten Kongstadbb520722023-04-26 13:16:41 +0200374 }
375 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200376 name: "b"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200377 description: "B"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200378 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200379 state: DISABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200380 permission: READ_WRITE
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200381 }
Mårten Kongstadbb520722023-04-26 13:16:41 +0200382 }
383 "#;
Mårten Kongstad30950782023-05-09 13:31:29 +0200384 let actual = Namespace::try_from_text_proto(s).unwrap();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200385
386 assert_eq!(expected, actual);
387 }
388
389 #[test]
390 fn test_override_try_from_text_proto_list() {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200391 let expected = Override {
Mårten Kongstad30950782023-05-09 13:31:29 +0200392 namespace: "ns".to_owned(),
393 name: "1234".to_owned(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200394 state: FlagState::Enabled,
395 permission: Permission::ReadOnly,
396 };
Mårten Kongstadbb520722023-04-26 13:16:41 +0200397
398 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200399 namespace: "ns"
400 name: "1234"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200401 state: ENABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200402 permission: READ_ONLY
Mårten Kongstadbb520722023-04-26 13:16:41 +0200403 "#;
404 let actual = Override::try_from_text_proto(s).unwrap();
405
406 assert_eq!(expected, actual);
407 }
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200408
409 #[test]
Mårten Kongstad416330b2023-05-05 11:10:01 +0200410 fn test_flag_resolve() {
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200411 let flag = Flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200412 name: "a".to_owned(),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200413 description: "A".to_owned(),
414 values: vec![
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200415 Value::default(FlagState::Disabled, Permission::ReadOnly),
416 Value::new(FlagState::Disabled, Permission::ReadWrite, 10),
417 Value::new(FlagState::Enabled, Permission::ReadOnly, 20),
418 Value::new(FlagState::Enabled, Permission::ReadWrite, 30),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200419 ],
420 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200421 assert_eq!((FlagState::Disabled, Permission::ReadOnly), flag.resolve(0));
422 assert_eq!((FlagState::Disabled, Permission::ReadOnly), flag.resolve(9));
423 assert_eq!((FlagState::Disabled, Permission::ReadWrite), flag.resolve(10));
424 assert_eq!((FlagState::Disabled, Permission::ReadWrite), flag.resolve(11));
425 assert_eq!((FlagState::Disabled, Permission::ReadWrite), flag.resolve(19));
426 assert_eq!((FlagState::Enabled, Permission::ReadOnly), flag.resolve(20));
427 assert_eq!((FlagState::Enabled, Permission::ReadOnly), flag.resolve(21));
428 assert_eq!((FlagState::Enabled, Permission::ReadOnly), flag.resolve(29));
429 assert_eq!((FlagState::Enabled, Permission::ReadWrite), flag.resolve(30));
430 assert_eq!((FlagState::Enabled, Permission::ReadWrite), flag.resolve(10_000));
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200431 }
Mårten Kongstadbb520722023-04-26 13:16:41 +0200432}