blob: 733b1c5d1fc0a6257b231a588817ee4798f64634 [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;
Joe Onorato0c4ef0f2023-05-13 11:30:11 -070019use std::path::PathBuf;
Zhi Doueb744892023-05-10 04:02:33 +000020use tinytemplate::TinyTemplate;
21
22use crate::aconfig::{FlagState, Permission};
23use crate::cache::{Cache, Item};
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020024use crate::commands::OutputFile;
Zhi Doueb744892023-05-10 04:02:33 +000025
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020026pub fn generate_java_code(cache: &Cache) -> Result<OutputFile> {
Zhi Doueb744892023-05-10 04:02:33 +000027 let class_elements: Vec<ClassElement> = cache.iter().map(create_class_element).collect();
28 let readwrite = class_elements.iter().any(|item| item.readwrite);
Joe Onorato0c4ef0f2023-05-13 11:30:11 -070029 let namespace = cache.namespace();
30 let context = Context { namespace: namespace.to_string(), readwrite, class_elements };
Zhi Doueb744892023-05-10 04:02:33 +000031 let mut template = TinyTemplate::new();
32 template.add_template("java_code_gen", include_str!("../templates/java.template"))?;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020033 let contents = template.render("java_code_gen", &context)?;
Joe Onorato0c4ef0f2023-05-13 11:30:11 -070034 let mut path: PathBuf = namespace.split('.').collect();
35 // TODO: Allow customization of the java class name
36 path.push("Flags.java");
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020037 Ok(OutputFile { contents: contents.into(), path })
Zhi Doueb744892023-05-10 04:02:33 +000038}
39
40#[derive(Serialize)]
41struct Context {
42 pub namespace: String,
43 pub readwrite: bool,
44 pub class_elements: Vec<ClassElement>,
45}
46
47#[derive(Serialize)]
48struct ClassElement {
49 pub method_name: String,
50 pub readwrite: bool,
51 pub default_value: String,
52 pub feature_name: String,
53 pub flag_name: String,
54}
55
56fn create_class_element(item: &Item) -> ClassElement {
57 ClassElement {
58 method_name: item.name.clone(),
59 readwrite: item.permission == Permission::ReadWrite,
60 default_value: if item.state == FlagState::Enabled {
61 "true".to_string()
62 } else {
63 "false".to_string()
64 },
65 feature_name: item.name.clone(),
66 flag_name: item.name.clone(),
67 }
68}
69
Zhi Doueb744892023-05-10 04:02:33 +000070#[cfg(test)]
71mod tests {
72 use super::*;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020073 use crate::aconfig::{FlagDeclaration, FlagValue};
Mårten Kongstad2f954442023-05-17 16:51:16 +020074 use crate::cache::CacheBuilder;
Zhi Doueb744892023-05-10 04:02:33 +000075 use crate::commands::Source;
76
77 #[test]
78 fn test_generate_java_code() {
Joe Onorato0c4ef0f2023-05-13 11:30:11 -070079 let namespace = "com.example";
Mårten Kongstad2f954442023-05-17 16:51:16 +020080 let mut builder = CacheBuilder::new(namespace.to_string()).unwrap();
81 builder
Mårten Kongstadfa23d292023-05-11 14:47:02 +020082 .add_flag_declaration(
Zhi Doueb744892023-05-10 04:02:33 +000083 Source::File("test.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +020084 FlagDeclaration {
Zhi Doueb744892023-05-10 04:02:33 +000085 name: "test".to_string(),
86 description: "buildtime enable".to_string(),
Zhi Doueb744892023-05-10 04:02:33 +000087 },
88 )
Mårten Kongstad2f954442023-05-17 16:51:16 +020089 .unwrap()
Mårten Kongstadfa23d292023-05-11 14:47:02 +020090 .add_flag_declaration(
Zhi Doueb744892023-05-10 04:02:33 +000091 Source::File("test2.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +020092 FlagDeclaration {
Zhi Doueb744892023-05-10 04:02:33 +000093 name: "test2".to_string(),
94 description: "runtime disable".to_string(),
Mårten Kongstadfa23d292023-05-11 14:47:02 +020095 },
96 )
Mårten Kongstad2f954442023-05-17 16:51:16 +020097 .unwrap()
Mårten Kongstadfa23d292023-05-11 14:47:02 +020098 .add_flag_value(
99 Source::Memory,
100 FlagValue {
101 namespace: namespace.to_string(),
102 name: "test".to_string(),
103 state: FlagState::Disabled,
104 permission: Permission::ReadOnly,
Zhi Doueb744892023-05-10 04:02:33 +0000105 },
106 )
107 .unwrap();
Mårten Kongstad2f954442023-05-17 16:51:16 +0200108 let cache = builder.build();
Joe Onorato0c4ef0f2023-05-13 11:30:11 -0700109 let expect_content = r#"package com.example;
Zhi Doueb744892023-05-10 04:02:33 +0000110
111 import android.provider.DeviceConfig;
112
Joe Onorato0c4ef0f2023-05-13 11:30:11 -0700113 public final class Flags {
Zhi Doueb744892023-05-10 04:02:33 +0000114
115 public static boolean test() {
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200116 return false;
Zhi Doueb744892023-05-10 04:02:33 +0000117 }
118
119 public static boolean test2() {
120 return DeviceConfig.getBoolean(
Joe Onorato0c4ef0f2023-05-13 11:30:11 -0700121 "com.example",
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +0200122 "test2__test2",
Zhi Doueb744892023-05-10 04:02:33 +0000123 false
124 );
125 }
126
127 }
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +0200128 "#;
129 let file = generate_java_code(&cache).unwrap();
Joe Onorato0c4ef0f2023-05-13 11:30:11 -0700130 assert_eq!("com/example/Flags.java", file.path.to_str().unwrap());
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +0200131 assert_eq!(
132 expect_content.replace(' ', ""),
133 String::from_utf8(file.contents).unwrap().replace(' ', "")
134 );
Zhi Doueb744892023-05-10 04:02:33 +0000135 }
136}