blob: 3a10f2ef0a6b03429c3ad399315d7792d4f9dced [file] [log] [blame]
Zhi Doueb744892023-05-10 04:02:33 +00001/*
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::Result;
18use serde::Serialize;
19use tinytemplate::TinyTemplate;
20
21use crate::aconfig::{FlagState, Permission};
22use crate::cache::{Cache, Item};
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020023use crate::commands::OutputFile;
Zhi Doueb744892023-05-10 04:02:33 +000024
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020025pub fn generate_java_code(cache: &Cache) -> Result<OutputFile> {
Zhi Doueb744892023-05-10 04:02:33 +000026 let class_elements: Vec<ClassElement> = cache.iter().map(create_class_element).collect();
27 let readwrite = class_elements.iter().any(|item| item.readwrite);
Mårten Kongstad6b9e3822023-05-16 11:19:58 +020028 let namespace = uppercase_first_letter(cache.namespace());
Zhi Doueb744892023-05-10 04:02:33 +000029 let context = Context { namespace: namespace.clone(), readwrite, class_elements };
30 let mut template = TinyTemplate::new();
31 template.add_template("java_code_gen", include_str!("../templates/java.template"))?;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020032 let contents = template.render("java_code_gen", &context)?;
33 let path = ["com", "android", "internal", "aconfig", &(namespace + ".java")].iter().collect();
34 Ok(OutputFile { contents: contents.into(), path })
Zhi Doueb744892023-05-10 04:02:33 +000035}
36
37#[derive(Serialize)]
38struct Context {
39 pub namespace: String,
40 pub readwrite: bool,
41 pub class_elements: Vec<ClassElement>,
42}
43
44#[derive(Serialize)]
45struct ClassElement {
46 pub method_name: String,
47 pub readwrite: bool,
48 pub default_value: String,
49 pub feature_name: String,
50 pub flag_name: String,
51}
52
53fn create_class_element(item: &Item) -> ClassElement {
54 ClassElement {
55 method_name: item.name.clone(),
56 readwrite: item.permission == Permission::ReadWrite,
57 default_value: if item.state == FlagState::Enabled {
58 "true".to_string()
59 } else {
60 "false".to_string()
61 },
62 feature_name: item.name.clone(),
63 flag_name: item.name.clone(),
64 }
65}
66
67fn uppercase_first_letter(s: &str) -> String {
68 s.chars()
69 .enumerate()
70 .map(
71 |(index, ch)| {
72 if index == 0 {
73 ch.to_ascii_uppercase()
74 } else {
75 ch.to_ascii_lowercase()
76 }
77 },
78 )
79 .collect()
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020085 use crate::aconfig::{FlagDeclaration, FlagValue};
Zhi Doueb744892023-05-10 04:02:33 +000086 use crate::commands::Source;
87
88 #[test]
89 fn test_generate_java_code() {
90 let namespace = "TeSTFlaG";
Mårten Kongstade17ba5f2023-05-16 12:52:43 +020091 let mut cache = Cache::new(namespace.to_string()).unwrap();
Zhi Doueb744892023-05-10 04:02:33 +000092 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +020093 .add_flag_declaration(
Zhi Doueb744892023-05-10 04:02:33 +000094 Source::File("test.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +020095 FlagDeclaration {
Zhi Doueb744892023-05-10 04:02:33 +000096 name: "test".to_string(),
97 description: "buildtime enable".to_string(),
Zhi Doueb744892023-05-10 04:02:33 +000098 },
99 )
100 .unwrap();
101 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200102 .add_flag_declaration(
Zhi Doueb744892023-05-10 04:02:33 +0000103 Source::File("test2.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200104 FlagDeclaration {
Zhi Doueb744892023-05-10 04:02:33 +0000105 name: "test2".to_string(),
106 description: "runtime disable".to_string(),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200107 },
108 )
109 .unwrap();
110 cache
111 .add_flag_value(
112 Source::Memory,
113 FlagValue {
114 namespace: namespace.to_string(),
115 name: "test".to_string(),
116 state: FlagState::Disabled,
117 permission: Permission::ReadOnly,
Zhi Doueb744892023-05-10 04:02:33 +0000118 },
119 )
120 .unwrap();
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +0200121 let expect_content = r#"package com.android.internal.aconfig;
Zhi Doueb744892023-05-10 04:02:33 +0000122
123 import android.provider.DeviceConfig;
124
125 public final class Testflag {
126
127 public static boolean test() {
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200128 return false;
Zhi Doueb744892023-05-10 04:02:33 +0000129 }
130
131 public static boolean test2() {
132 return DeviceConfig.getBoolean(
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +0200133 "Testflag",
134 "test2__test2",
Zhi Doueb744892023-05-10 04:02:33 +0000135 false
136 );
137 }
138
139 }
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +0200140 "#;
141 let file = generate_java_code(&cache).unwrap();
142 assert_eq!("com/android/internal/aconfig/Testflag.java", file.path.to_str().unwrap());
143 assert_eq!(
144 expect_content.replace(' ', ""),
145 String::from_utf8(file.contents).unwrap().replace(' ', "")
146 );
Zhi Doueb744892023-05-10 04:02:33 +0000147 }
148}