• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 use anyhow::{ensure, Result};
18 use serde::Serialize;
19 use std::collections::HashMap;
20 use std::path::PathBuf;
21 use tinytemplate::TinyTemplate;
22 
23 use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
24 
25 use crate::codegen;
26 use crate::codegen::CodegenMode;
27 use crate::commands::OutputFile;
28 
generate_cpp_code<I>( package: &str, parsed_flags_iter: I, codegen_mode: CodegenMode, flag_ids: HashMap<String, u16>, allow_instrumentation: bool, ) -> Result<Vec<OutputFile>> where I: Iterator<Item = ProtoParsedFlag>,29 pub fn generate_cpp_code<I>(
30     package: &str,
31     parsed_flags_iter: I,
32     codegen_mode: CodegenMode,
33     flag_ids: HashMap<String, u16>,
34     allow_instrumentation: bool,
35 ) -> Result<Vec<OutputFile>>
36 where
37     I: Iterator<Item = ProtoParsedFlag>,
38 {
39     let mut readwrite_count = 0;
40     let class_elements: Vec<ClassElement> = parsed_flags_iter
41         .map(|pf| create_class_element(package, &pf, flag_ids.clone(), &mut readwrite_count))
42         .collect();
43     let readwrite = readwrite_count > 0;
44     let has_fixed_read_only = class_elements.iter().any(|item| item.is_fixed_read_only);
45     let header = package.replace('.', "_");
46     let package_macro = header.to_uppercase();
47     let cpp_namespace = package.replace('.', "::");
48     ensure!(codegen::is_valid_name_ident(&header));
49     let context = Context {
50         header: &header,
51         package_macro: &package_macro,
52         cpp_namespace: &cpp_namespace,
53         package,
54         has_fixed_read_only,
55         readwrite,
56         readwrite_count,
57         is_test_mode: codegen_mode == CodegenMode::Test,
58         class_elements,
59         allow_instrumentation,
60     };
61 
62     let files = [
63         FileSpec {
64             name: &format!("{}.h", header),
65             template: include_str!("../../templates/cpp_exported_header.template"),
66             dir: "include",
67         },
68         FileSpec {
69             name: &format!("{}.cc", header),
70             template: include_str!("../../templates/cpp_source_file.template"),
71             dir: "",
72         },
73     ];
74     files.iter().map(|file| generate_file(file, &context)).collect()
75 }
76 
generate_file(file: &FileSpec, context: &Context) -> Result<OutputFile>77 pub fn generate_file(file: &FileSpec, context: &Context) -> Result<OutputFile> {
78     let mut template = TinyTemplate::new();
79     template.add_template(file.name, file.template)?;
80     let contents = template.render(file.name, &context)?;
81     let path: PathBuf = [&file.dir, &file.name].iter().collect();
82     Ok(OutputFile { contents: contents.into(), path })
83 }
84 
85 #[derive(Serialize)]
86 pub struct FileSpec<'a> {
87     pub name: &'a str,
88     pub template: &'a str,
89     pub dir: &'a str,
90 }
91 
92 #[derive(Serialize)]
93 pub struct Context<'a> {
94     pub header: &'a str,
95     pub package_macro: &'a str,
96     pub cpp_namespace: &'a str,
97     pub package: &'a str,
98     pub has_fixed_read_only: bool,
99     pub readwrite: bool,
100     pub readwrite_count: i32,
101     pub is_test_mode: bool,
102     pub class_elements: Vec<ClassElement>,
103     pub allow_instrumentation: bool,
104 }
105 
106 #[derive(Serialize)]
107 pub struct ClassElement {
108     pub readwrite_idx: i32,
109     pub readwrite: bool,
110     pub is_fixed_read_only: bool,
111     pub default_value: String,
112     pub flag_name: String,
113     pub flag_macro: String,
114     pub flag_offset: u16,
115     pub device_config_namespace: String,
116     pub device_config_flag: String,
117     pub container: String,
118 }
119 
create_class_element( package: &str, pf: &ProtoParsedFlag, flag_ids: HashMap<String, u16>, rw_count: &mut i32, ) -> ClassElement120 fn create_class_element(
121     package: &str,
122     pf: &ProtoParsedFlag,
123     flag_ids: HashMap<String, u16>,
124     rw_count: &mut i32,
125 ) -> ClassElement {
126     ClassElement {
127         readwrite_idx: if pf.permission() == ProtoFlagPermission::READ_WRITE {
128             let index = *rw_count;
129             *rw_count += 1;
130             index
131         } else {
132             -1
133         },
134         readwrite: pf.permission() == ProtoFlagPermission::READ_WRITE,
135         is_fixed_read_only: pf.is_fixed_read_only(),
136         default_value: if pf.state() == ProtoFlagState::ENABLED {
137             "true".to_string()
138         } else {
139             "false".to_string()
140         },
141         flag_name: pf.name().to_string(),
142         flag_macro: pf.name().to_uppercase(),
143         flag_offset: *flag_ids.get(pf.name()).expect("values checked at flag parse time"),
144         device_config_namespace: pf.namespace().to_string(),
145         device_config_flag: codegen::create_device_config_ident(package, pf.name())
146             .expect("values checked at flag parse time"),
147         container: pf.container().to_string(),
148     }
149 }
150 
151 #[cfg(test)]
152 mod tests {
153     use super::*;
154     use aconfig_protos::ProtoParsedFlags;
155     use std::collections::HashMap;
156 
157     const EXPORTED_PROD_HEADER_EXPECTED: &str = r#"
158 #pragma once
159 
160 #ifndef COM_ANDROID_ACONFIG_TEST
161 #define COM_ANDROID_ACONFIG_TEST(FLAG) COM_ANDROID_ACONFIG_TEST_##FLAG
162 #endif
163 
164 #ifndef COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO
165 #define COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO true
166 #endif
167 
168 #ifndef COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO_EXPORTED
169 #define COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO_EXPORTED true
170 #endif
171 
172 #ifdef __cplusplus
173 
174 #include <memory>
175 
176 namespace com::android::aconfig::test {
177 
178 class flag_provider_interface {
179 public:
180     virtual ~flag_provider_interface() = default;
181 
182     virtual bool disabled_ro() = 0;
183 
184     virtual bool disabled_rw() = 0;
185 
186     virtual bool disabled_rw_exported() = 0;
187 
188     virtual bool disabled_rw_in_other_namespace() = 0;
189 
190     virtual bool enabled_fixed_ro() = 0;
191 
192     virtual bool enabled_fixed_ro_exported() = 0;
193 
194     virtual bool enabled_ro() = 0;
195 
196     virtual bool enabled_ro_exported() = 0;
197 
198     virtual bool enabled_rw() = 0;
199 };
200 
201 extern std::unique_ptr<flag_provider_interface> provider_;
202 
203 inline bool disabled_ro() {
204     return false;
205 }
206 
207 inline bool disabled_rw() {
208     return provider_->disabled_rw();
209 }
210 
211 inline bool disabled_rw_exported() {
212     return provider_->disabled_rw_exported();
213 }
214 
215 inline bool disabled_rw_in_other_namespace() {
216     return provider_->disabled_rw_in_other_namespace();
217 }
218 
219 inline bool enabled_fixed_ro() {
220     return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
221 }
222 
223 inline bool enabled_fixed_ro_exported() {
224     return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO_EXPORTED;
225 }
226 
227 inline bool enabled_ro() {
228     return true;
229 }
230 
231 inline bool enabled_ro_exported() {
232     return true;
233 }
234 
235 inline bool enabled_rw() {
236     return provider_->enabled_rw();
237 }
238 
239 }
240 
241 extern "C" {
242 #endif // __cplusplus
243 
244 bool com_android_aconfig_test_disabled_ro();
245 
246 bool com_android_aconfig_test_disabled_rw();
247 
248 bool com_android_aconfig_test_disabled_rw_exported();
249 
250 bool com_android_aconfig_test_disabled_rw_in_other_namespace();
251 
252 bool com_android_aconfig_test_enabled_fixed_ro();
253 
254 bool com_android_aconfig_test_enabled_fixed_ro_exported();
255 
256 bool com_android_aconfig_test_enabled_ro();
257 
258 bool com_android_aconfig_test_enabled_ro_exported();
259 
260 bool com_android_aconfig_test_enabled_rw();
261 
262 #ifdef __cplusplus
263 } // extern "C"
264 #endif
265 "#;
266 
267     const EXPORTED_TEST_HEADER_EXPECTED: &str = r#"
268 #pragma once
269 
270 #ifdef __cplusplus
271 
272 #include <memory>
273 
274 namespace com::android::aconfig::test {
275 
276 class flag_provider_interface {
277 public:
278 
279     virtual ~flag_provider_interface() = default;
280 
281     virtual bool disabled_ro() = 0;
282 
283     virtual void disabled_ro(bool val) = 0;
284 
285     virtual bool disabled_rw() = 0;
286 
287     virtual void disabled_rw(bool val) = 0;
288 
289     virtual bool disabled_rw_exported() = 0;
290 
291     virtual void disabled_rw_exported(bool val) = 0;
292 
293     virtual bool disabled_rw_in_other_namespace() = 0;
294 
295     virtual void disabled_rw_in_other_namespace(bool val) = 0;
296 
297     virtual bool enabled_fixed_ro() = 0;
298 
299     virtual void enabled_fixed_ro(bool val) = 0;
300 
301     virtual bool enabled_fixed_ro_exported() = 0;
302 
303     virtual void enabled_fixed_ro_exported(bool val) = 0;
304 
305     virtual bool enabled_ro() = 0;
306 
307     virtual void enabled_ro(bool val) = 0;
308 
309     virtual bool enabled_ro_exported() = 0;
310 
311     virtual void enabled_ro_exported(bool val) = 0;
312 
313     virtual bool enabled_rw() = 0;
314 
315     virtual void enabled_rw(bool val) = 0;
316 
317     virtual void reset_flags() {}
318 };
319 
320 extern std::unique_ptr<flag_provider_interface> provider_;
321 
322 inline bool disabled_ro() {
323     return provider_->disabled_ro();
324 }
325 
326 inline void disabled_ro(bool val) {
327     provider_->disabled_ro(val);
328 }
329 
330 inline bool disabled_rw() {
331     return provider_->disabled_rw();
332 }
333 
334 inline void disabled_rw(bool val) {
335     provider_->disabled_rw(val);
336 }
337 
338 inline bool disabled_rw_exported() {
339     return provider_->disabled_rw_exported();
340 }
341 
342 inline void disabled_rw_exported(bool val) {
343     provider_->disabled_rw_exported(val);
344 }
345 
346 inline bool disabled_rw_in_other_namespace() {
347     return provider_->disabled_rw_in_other_namespace();
348 }
349 
350 inline void disabled_rw_in_other_namespace(bool val) {
351     provider_->disabled_rw_in_other_namespace(val);
352 }
353 
354 inline bool enabled_fixed_ro() {
355     return provider_->enabled_fixed_ro();
356 }
357 
358 inline void enabled_fixed_ro(bool val) {
359     provider_->enabled_fixed_ro(val);
360 }
361 
362 inline bool enabled_fixed_ro_exported() {
363     return provider_->enabled_fixed_ro_exported();
364 }
365 
366 inline void enabled_fixed_ro_exported(bool val) {
367     provider_->enabled_fixed_ro_exported(val);
368 }
369 
370 inline bool enabled_ro() {
371     return provider_->enabled_ro();
372 }
373 
374 inline void enabled_ro(bool val) {
375     provider_->enabled_ro(val);
376 }
377 
378 inline bool enabled_ro_exported() {
379     return provider_->enabled_ro_exported();
380 }
381 
382 inline void enabled_ro_exported(bool val) {
383     provider_->enabled_ro_exported(val);
384 }
385 
386 inline bool enabled_rw() {
387     return provider_->enabled_rw();
388 }
389 
390 inline void enabled_rw(bool val) {
391     provider_->enabled_rw(val);
392 }
393 
394 inline void reset_flags() {
395     return provider_->reset_flags();
396 }
397 
398 }
399 
400 extern "C" {
401 #endif // __cplusplus
402 
403 bool com_android_aconfig_test_disabled_ro();
404 
405 void set_com_android_aconfig_test_disabled_ro(bool val);
406 
407 bool com_android_aconfig_test_disabled_rw();
408 
409 void set_com_android_aconfig_test_disabled_rw(bool val);
410 
411 bool com_android_aconfig_test_disabled_rw_exported();
412 
413 void set_com_android_aconfig_test_disabled_rw_exported(bool val);
414 
415 bool com_android_aconfig_test_disabled_rw_in_other_namespace();
416 
417 void set_com_android_aconfig_test_disabled_rw_in_other_namespace(bool val);
418 
419 bool com_android_aconfig_test_enabled_fixed_ro();
420 
421 void set_com_android_aconfig_test_enabled_fixed_ro(bool val);
422 
423 bool com_android_aconfig_test_enabled_fixed_ro_exported();
424 
425 void set_com_android_aconfig_test_enabled_fixed_ro_exported(bool val);
426 
427 bool com_android_aconfig_test_enabled_ro();
428 
429 void set_com_android_aconfig_test_enabled_ro(bool val);
430 
431 bool com_android_aconfig_test_enabled_ro_exported();
432 
433 void set_com_android_aconfig_test_enabled_ro_exported(bool val);
434 
435 bool com_android_aconfig_test_enabled_rw();
436 
437 void set_com_android_aconfig_test_enabled_rw(bool val);
438 
439 void com_android_aconfig_test_reset_flags();
440 
441 
442 #ifdef __cplusplus
443 } // extern "C"
444 #endif
445 
446 
447 "#;
448 
449     const EXPORTED_EXPORTED_HEADER_EXPECTED: &str = r#"
450 #pragma once
451 
452 #ifdef __cplusplus
453 
454 #include <memory>
455 
456 namespace com::android::aconfig::test {
457 
458 class flag_provider_interface {
459 public:
460     virtual ~flag_provider_interface() = default;
461 
462     virtual bool disabled_rw_exported() = 0;
463 
464     virtual bool enabled_fixed_ro_exported() = 0;
465 
466     virtual bool enabled_ro_exported() = 0;
467 };
468 
469 extern std::unique_ptr<flag_provider_interface> provider_;
470 
471 inline bool disabled_rw_exported() {
472     return provider_->disabled_rw_exported();
473 }
474 
475 inline bool enabled_fixed_ro_exported() {
476     return provider_->enabled_fixed_ro_exported();
477 }
478 
479 inline bool enabled_ro_exported() {
480     return provider_->enabled_ro_exported();
481 }
482 
483 }
484 
485 extern "C" {
486 #endif // __cplusplus
487 
488 bool com_android_aconfig_test_disabled_rw_exported();
489 
490 bool com_android_aconfig_test_enabled_fixed_ro_exported();
491 
492 bool com_android_aconfig_test_enabled_ro_exported();
493 
494 #ifdef __cplusplus
495 } // extern "C"
496 #endif
497 "#;
498 
499     const EXPORTED_FORCE_READ_ONLY_HEADER_EXPECTED: &str = r#"
500 #pragma once
501 
502 #ifndef COM_ANDROID_ACONFIG_TEST
503 #define COM_ANDROID_ACONFIG_TEST(FLAG) COM_ANDROID_ACONFIG_TEST_##FLAG
504 #endif
505 
506 #ifndef COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO
507 #define COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO true
508 #endif
509 
510 #ifdef __cplusplus
511 
512 #include <memory>
513 
514 namespace com::android::aconfig::test {
515 
516 class flag_provider_interface {
517 public:
518     virtual ~flag_provider_interface() = default;
519 
520     virtual bool disabled_ro() = 0;
521 
522     virtual bool disabled_rw() = 0;
523 
524     virtual bool disabled_rw_in_other_namespace() = 0;
525 
526     virtual bool enabled_fixed_ro() = 0;
527 
528     virtual bool enabled_ro() = 0;
529 
530     virtual bool enabled_rw() = 0;
531 };
532 
533 extern std::unique_ptr<flag_provider_interface> provider_;
534 
535 inline bool disabled_ro() {
536     return false;
537 }
538 
539 inline bool disabled_rw() {
540     return false;
541 }
542 
543 inline bool disabled_rw_in_other_namespace() {
544     return false;
545 }
546 
547 inline bool enabled_fixed_ro() {
548     return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
549 }
550 
551 inline bool enabled_ro() {
552     return true;
553 }
554 
555 inline bool enabled_rw() {
556     return true;
557 }
558 
559 }
560 
561 extern "C" {
562 #endif // __cplusplus
563 
564 bool com_android_aconfig_test_disabled_ro();
565 
566 bool com_android_aconfig_test_disabled_rw();
567 
568 bool com_android_aconfig_test_disabled_rw_in_other_namespace();
569 
570 bool com_android_aconfig_test_enabled_fixed_ro();
571 
572 bool com_android_aconfig_test_enabled_ro();
573 
574 bool com_android_aconfig_test_enabled_rw();
575 
576 #ifdef __cplusplus
577 } // extern "C"
578 #endif
579 "#;
580 
581     const PROD_SOURCE_FILE_EXPECTED: &str = r#"
582 #include "com_android_aconfig_test.h"
583 #include <server_configurable_flags/get_flags.h>
584 #include <vector>
585 
586 namespace com::android::aconfig::test {
587 
588     class flag_provider : public flag_provider_interface {
589         public:
590 
591             virtual bool disabled_ro() override {
592                 return false;
593             }
594 
595             virtual bool disabled_rw() override {
596                 if (cache_[0] == -1) {
597                     cache_[0] = server_configurable_flags::GetServerConfigurableFlag(
598                         "aconfig_flags.aconfig_test",
599                         "com.android.aconfig.test.disabled_rw",
600                         "false") == "true";
601                 }
602                 return cache_[0];
603             }
604 
605             virtual bool disabled_rw_exported() override {
606                 if (cache_[1] == -1) {
607                     cache_[1] = server_configurable_flags::GetServerConfigurableFlag(
608                         "aconfig_flags.aconfig_test",
609                         "com.android.aconfig.test.disabled_rw_exported",
610                         "false") == "true";
611                 }
612                 return cache_[1];
613             }
614 
615             virtual bool disabled_rw_in_other_namespace() override {
616                 if (cache_[2] == -1) {
617                     cache_[2] = server_configurable_flags::GetServerConfigurableFlag(
618                         "aconfig_flags.other_namespace",
619                         "com.android.aconfig.test.disabled_rw_in_other_namespace",
620                         "false") == "true";
621                 }
622                 return cache_[2];
623             }
624 
625             virtual bool enabled_fixed_ro() override {
626                 return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
627             }
628 
629             virtual bool enabled_fixed_ro_exported() override {
630                 return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO_EXPORTED;
631             }
632 
633             virtual bool enabled_ro() override {
634                 return true;
635             }
636 
637             virtual bool enabled_ro_exported() override {
638                 return true;
639             }
640 
641             virtual bool enabled_rw() override {
642                 if (cache_[3] == -1) {
643                     cache_[3] = server_configurable_flags::GetServerConfigurableFlag(
644                         "aconfig_flags.aconfig_test",
645                         "com.android.aconfig.test.enabled_rw",
646                         "true") == "true";
647                 }
648                 return cache_[3];
649             }
650 
651     private:
652         std::vector<int8_t> cache_ = std::vector<int8_t>(4, -1);
653     };
654 
655     std::unique_ptr<flag_provider_interface> provider_ =
656         std::make_unique<flag_provider>();
657 }
658 
659 bool com_android_aconfig_test_disabled_ro() {
660     return false;
661 }
662 
663 bool com_android_aconfig_test_disabled_rw() {
664     return com::android::aconfig::test::disabled_rw();
665 }
666 
667 bool com_android_aconfig_test_disabled_rw_exported() {
668     return com::android::aconfig::test::disabled_rw_exported();
669 }
670 
671 bool com_android_aconfig_test_disabled_rw_in_other_namespace() {
672     return com::android::aconfig::test::disabled_rw_in_other_namespace();
673 }
674 
675 bool com_android_aconfig_test_enabled_fixed_ro() {
676     return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
677 }
678 
679 bool com_android_aconfig_test_enabled_fixed_ro_exported() {
680     return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO_EXPORTED;
681 }
682 
683 bool com_android_aconfig_test_enabled_ro() {
684     return true;
685 }
686 
687 bool com_android_aconfig_test_enabled_ro_exported() {
688     return true;
689 }
690 
691 bool com_android_aconfig_test_enabled_rw() {
692     return com::android::aconfig::test::enabled_rw();
693 }
694 
695 "#;
696 
697     const TEST_SOURCE_FILE_EXPECTED: &str = r#"
698 #include "com_android_aconfig_test.h"
699 #include <server_configurable_flags/get_flags.h>
700 #include <unordered_map>
701 #include <string>
702 
703 namespace com::android::aconfig::test {
704 
705     class flag_provider : public flag_provider_interface {
706         private:
707             std::unordered_map<std::string, bool> overrides_;
708 
709         public:
710             flag_provider()
711                 : overrides_()
712             {}
713 
714             virtual bool disabled_ro() override {
715                 auto it = overrides_.find("disabled_ro");
716                   if (it != overrides_.end()) {
717                       return it->second;
718                 } else {
719                   return false;
720                 }
721             }
722 
723             virtual void disabled_ro(bool val) override {
724                 overrides_["disabled_ro"] = val;
725             }
726 
727             virtual bool disabled_rw() override {
728                 auto it = overrides_.find("disabled_rw");
729                   if (it != overrides_.end()) {
730                       return it->second;
731                 } else {
732                   return server_configurable_flags::GetServerConfigurableFlag(
733                       "aconfig_flags.aconfig_test",
734                       "com.android.aconfig.test.disabled_rw",
735                       "false") == "true";
736                 }
737             }
738 
739             virtual void disabled_rw(bool val) override {
740                 overrides_["disabled_rw"] = val;
741             }
742 
743             virtual bool disabled_rw_exported() override {
744                 auto it = overrides_.find("disabled_rw_exported");
745                   if (it != overrides_.end()) {
746                       return it->second;
747                 } else {
748                   return server_configurable_flags::GetServerConfigurableFlag(
749                       "aconfig_flags.aconfig_test",
750                       "com.android.aconfig.test.disabled_rw_exported",
751                       "false") == "true";
752                 }
753             }
754 
755             virtual void disabled_rw_exported(bool val) override {
756                 overrides_["disabled_rw_exported"] = val;
757             }
758 
759             virtual bool disabled_rw_in_other_namespace() override {
760                 auto it = overrides_.find("disabled_rw_in_other_namespace");
761                   if (it != overrides_.end()) {
762                       return it->second;
763                 } else {
764                   return server_configurable_flags::GetServerConfigurableFlag(
765                       "aconfig_flags.other_namespace",
766                       "com.android.aconfig.test.disabled_rw_in_other_namespace",
767                       "false") == "true";
768                 }
769             }
770 
771             virtual void disabled_rw_in_other_namespace(bool val) override {
772                 overrides_["disabled_rw_in_other_namespace"] = val;
773             }
774 
775             virtual bool enabled_fixed_ro() override {
776                 auto it = overrides_.find("enabled_fixed_ro");
777                   if (it != overrides_.end()) {
778                       return it->second;
779                 } else {
780                   return true;
781                 }
782             }
783 
784             virtual void enabled_fixed_ro(bool val) override {
785                 overrides_["enabled_fixed_ro"] = val;
786             }
787 
788             virtual bool enabled_fixed_ro_exported() override {
789                 auto it = overrides_.find("enabled_fixed_ro_exported");
790                   if (it != overrides_.end()) {
791                       return it->second;
792                 } else {
793                   return true;
794                 }
795             }
796 
797             virtual void enabled_fixed_ro_exported(bool val) override {
798                 overrides_["enabled_fixed_ro_exported"] = val;
799             }
800 
801             virtual bool enabled_ro() override {
802                 auto it = overrides_.find("enabled_ro");
803                   if (it != overrides_.end()) {
804                       return it->second;
805                 } else {
806                   return true;
807                 }
808             }
809 
810             virtual void enabled_ro(bool val) override {
811                 overrides_["enabled_ro"] = val;
812             }
813 
814             virtual bool enabled_ro_exported() override {
815                 auto it = overrides_.find("enabled_ro_exported");
816                   if (it != overrides_.end()) {
817                       return it->second;
818                 } else {
819                   return true;
820                 }
821             }
822 
823             virtual void enabled_ro_exported(bool val) override {
824                 overrides_["enabled_ro_exported"] = val;
825             }
826 
827             virtual bool enabled_rw() override {
828                 auto it = overrides_.find("enabled_rw");
829                   if (it != overrides_.end()) {
830                       return it->second;
831                 } else {
832                   return server_configurable_flags::GetServerConfigurableFlag(
833                       "aconfig_flags.aconfig_test",
834                       "com.android.aconfig.test.enabled_rw",
835                       "true") == "true";
836                 }
837             }
838 
839             virtual void enabled_rw(bool val) override {
840                 overrides_["enabled_rw"] = val;
841             }
842 
843             virtual void reset_flags() override {
844                 overrides_.clear();
845             }
846     };
847 
848     std::unique_ptr<flag_provider_interface> provider_ =
849         std::make_unique<flag_provider>();
850 }
851 
852 bool com_android_aconfig_test_disabled_ro() {
853     return com::android::aconfig::test::disabled_ro();
854 }
855 
856 
857 void set_com_android_aconfig_test_disabled_ro(bool val) {
858     com::android::aconfig::test::disabled_ro(val);
859 }
860 
861 bool com_android_aconfig_test_disabled_rw() {
862     return com::android::aconfig::test::disabled_rw();
863 }
864 
865 
866 void set_com_android_aconfig_test_disabled_rw(bool val) {
867     com::android::aconfig::test::disabled_rw(val);
868 }
869 
870 
871 bool com_android_aconfig_test_disabled_rw_exported() {
872     return com::android::aconfig::test::disabled_rw_exported();
873 }
874 
875 void set_com_android_aconfig_test_disabled_rw_exported(bool val) {
876     com::android::aconfig::test::disabled_rw_exported(val);
877 }
878 
879 
880 bool com_android_aconfig_test_disabled_rw_in_other_namespace() {
881     return com::android::aconfig::test::disabled_rw_in_other_namespace();
882 }
883 
884 void set_com_android_aconfig_test_disabled_rw_in_other_namespace(bool val) {
885     com::android::aconfig::test::disabled_rw_in_other_namespace(val);
886 }
887 
888 
889 bool com_android_aconfig_test_enabled_fixed_ro() {
890     return com::android::aconfig::test::enabled_fixed_ro();
891 }
892 
893 void set_com_android_aconfig_test_enabled_fixed_ro(bool val) {
894     com::android::aconfig::test::enabled_fixed_ro(val);
895 }
896 
897 bool com_android_aconfig_test_enabled_fixed_ro_exported() {
898     return com::android::aconfig::test::enabled_fixed_ro_exported();
899 }
900 
901 void set_com_android_aconfig_test_enabled_fixed_ro_exported(bool val) {
902     com::android::aconfig::test::enabled_fixed_ro_exported(val);
903 }
904 
905 bool com_android_aconfig_test_enabled_ro() {
906     return com::android::aconfig::test::enabled_ro();
907 }
908 
909 
910 void set_com_android_aconfig_test_enabled_ro(bool val) {
911     com::android::aconfig::test::enabled_ro(val);
912 }
913 
914 
915 bool com_android_aconfig_test_enabled_ro_exported() {
916     return com::android::aconfig::test::enabled_ro_exported();
917 }
918 
919 
920 void set_com_android_aconfig_test_enabled_ro_exported(bool val) {
921     com::android::aconfig::test::enabled_ro_exported(val);
922 }
923 
924 
925 bool com_android_aconfig_test_enabled_rw() {
926     return com::android::aconfig::test::enabled_rw();
927 }
928 
929 
930 void set_com_android_aconfig_test_enabled_rw(bool val) {
931     com::android::aconfig::test::enabled_rw(val);
932 }
933 
934 void com_android_aconfig_test_reset_flags() {
935      com::android::aconfig::test::reset_flags();
936 }
937 
938 "#;
939 
940     const EXPORTED_SOURCE_FILE_EXPECTED: &str = r#"
941 #include "com_android_aconfig_test.h"
942 #include <server_configurable_flags/get_flags.h>
943 #include <vector>
944 
945 namespace com::android::aconfig::test {
946 
947     class flag_provider : public flag_provider_interface {
948         public:
949             virtual bool disabled_rw_exported() override {
950                 if (cache_[0] == -1) {
951                     cache_[0] = server_configurable_flags::GetServerConfigurableFlag(
952                         "aconfig_flags.aconfig_test",
953                         "com.android.aconfig.test.disabled_rw_exported",
954                         "false") == "true";
955                 }
956                 return cache_[0];
957             }
958 
959             virtual bool enabled_fixed_ro_exported() override {
960                 if (cache_[1] == -1) {
961                     cache_[1] = server_configurable_flags::GetServerConfigurableFlag(
962                         "aconfig_flags.aconfig_test",
963                         "com.android.aconfig.test.enabled_fixed_ro_exported",
964                         "false") == "true";
965                 }
966                 return cache_[1];
967             }
968 
969             virtual bool enabled_ro_exported() override {
970                 if (cache_[2] == -1) {
971                     cache_[2] = server_configurable_flags::GetServerConfigurableFlag(
972                         "aconfig_flags.aconfig_test",
973                         "com.android.aconfig.test.enabled_ro_exported",
974                         "false") == "true";
975                 }
976                 return cache_[2];
977             }
978 
979     private:
980         std::vector<int8_t> cache_ = std::vector<int8_t>(3, -1);
981     };
982 
983     std::unique_ptr<flag_provider_interface> provider_ =
984         std::make_unique<flag_provider>();
985 }
986 
987 bool com_android_aconfig_test_disabled_rw_exported() {
988     return com::android::aconfig::test::disabled_rw_exported();
989 }
990 
991 bool com_android_aconfig_test_enabled_fixed_ro_exported() {
992     return com::android::aconfig::test::enabled_fixed_ro_exported();
993 }
994 
995 bool com_android_aconfig_test_enabled_ro_exported() {
996     return com::android::aconfig::test::enabled_ro_exported();
997 }
998 
999 
1000 "#;
1001 
1002     const FORCE_READ_ONLY_SOURCE_FILE_EXPECTED: &str = r#"
1003 #include "com_android_aconfig_test.h"
1004 
1005 namespace com::android::aconfig::test {
1006 
1007     class flag_provider : public flag_provider_interface {
1008         public:
1009 
1010             virtual bool disabled_ro() override {
1011                 return false;
1012             }
1013 
1014             virtual bool disabled_rw() override {
1015                 return false;
1016             }
1017 
1018             virtual bool disabled_rw_in_other_namespace() override {
1019                 return false;
1020             }
1021 
1022             virtual bool enabled_fixed_ro() override {
1023                 return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
1024             }
1025 
1026             virtual bool enabled_ro() override {
1027                 return true;
1028             }
1029 
1030             virtual bool enabled_rw() override {
1031                 return true;
1032             }
1033     };
1034 
1035     std::unique_ptr<flag_provider_interface> provider_ =
1036         std::make_unique<flag_provider>();
1037 }
1038 
1039 bool com_android_aconfig_test_disabled_ro() {
1040     return false;
1041 }
1042 
1043 bool com_android_aconfig_test_disabled_rw() {
1044     return false;
1045 }
1046 
1047 bool com_android_aconfig_test_disabled_rw_in_other_namespace() {
1048     return false;
1049 }
1050 
1051 bool com_android_aconfig_test_enabled_fixed_ro() {
1052     return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
1053 }
1054 
1055 bool com_android_aconfig_test_enabled_ro() {
1056     return true;
1057 }
1058 
1059 bool com_android_aconfig_test_enabled_rw() {
1060     return true;
1061 }
1062 
1063 "#;
1064 
1065     const READ_ONLY_EXPORTED_PROD_HEADER_EXPECTED: &str = r#"
1066 #pragma once
1067 
1068 #ifndef COM_ANDROID_ACONFIG_TEST
1069 #define COM_ANDROID_ACONFIG_TEST(FLAG) COM_ANDROID_ACONFIG_TEST_##FLAG
1070 #endif
1071 
1072 #ifndef COM_ANDROID_ACONFIG_TEST_DISABLED_FIXED_RO
1073 #define COM_ANDROID_ACONFIG_TEST_DISABLED_FIXED_RO false
1074 #endif
1075 
1076 #ifndef COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO
1077 #define COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO true
1078 #endif
1079 
1080 #ifdef __cplusplus
1081 
1082 #include <memory>
1083 
1084 namespace com::android::aconfig::test {
1085 
1086 class flag_provider_interface {
1087 public:
1088     virtual ~flag_provider_interface() = default;
1089 
1090     virtual bool disabled_fixed_ro() = 0;
1091 
1092     virtual bool disabled_ro() = 0;
1093 
1094     virtual bool enabled_fixed_ro() = 0;
1095 
1096     virtual bool enabled_ro() = 0;
1097 };
1098 
1099 extern std::unique_ptr<flag_provider_interface> provider_;
1100 
1101 inline bool disabled_fixed_ro() {
1102     return COM_ANDROID_ACONFIG_TEST_DISABLED_FIXED_RO;
1103 }
1104 
1105 inline bool disabled_ro() {
1106     return false;
1107 }
1108 
1109 inline bool enabled_fixed_ro() {
1110     return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
1111 }
1112 
1113 inline bool enabled_ro() {
1114     return true;
1115 }
1116 }
1117 
1118 extern "C" {
1119 #endif // __cplusplus
1120 
1121 bool com_android_aconfig_test_disabled_fixed_ro();
1122 
1123 bool com_android_aconfig_test_disabled_ro();
1124 
1125 bool com_android_aconfig_test_enabled_fixed_ro();
1126 
1127 bool com_android_aconfig_test_enabled_ro();
1128 
1129 #ifdef __cplusplus
1130 } // extern "C"
1131 #endif
1132 "#;
1133 
1134     const READ_ONLY_PROD_SOURCE_FILE_EXPECTED: &str = r#"
1135 #include "com_android_aconfig_test.h"
1136 
1137 namespace com::android::aconfig::test {
1138 
1139     class flag_provider : public flag_provider_interface {
1140         public:
1141 
1142             virtual bool disabled_fixed_ro() override {
1143                 return COM_ANDROID_ACONFIG_TEST_DISABLED_FIXED_RO;
1144             }
1145 
1146             virtual bool disabled_ro() override {
1147                 return false;
1148             }
1149 
1150             virtual bool enabled_fixed_ro() override {
1151                 return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
1152             }
1153 
1154             virtual bool enabled_ro() override {
1155                 return true;
1156             }
1157     };
1158 
1159     std::unique_ptr<flag_provider_interface> provider_ =
1160         std::make_unique<flag_provider>();
1161 }
1162 
1163 bool com_android_aconfig_test_disabled_fixed_ro() {
1164     return COM_ANDROID_ACONFIG_TEST_DISABLED_FIXED_RO;
1165 }
1166 
1167 bool com_android_aconfig_test_disabled_ro() {
1168     return false;
1169 }
1170 
1171 bool com_android_aconfig_test_enabled_fixed_ro() {
1172     return COM_ANDROID_ACONFIG_TEST_ENABLED_FIXED_RO;
1173 }
1174 
1175 bool com_android_aconfig_test_enabled_ro() {
1176     return true;
1177 }
1178 "#;
1179     use crate::commands::assign_flag_ids;
1180 
test_generate_cpp_code( parsed_flags: ProtoParsedFlags, mode: CodegenMode, expected_header: &str, expected_src: &str, allow_instrumentation: bool, )1181     fn test_generate_cpp_code(
1182         parsed_flags: ProtoParsedFlags,
1183         mode: CodegenMode,
1184         expected_header: &str,
1185         expected_src: &str,
1186         allow_instrumentation: bool,
1187     ) {
1188         let modified_parsed_flags =
1189             crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
1190         let flag_ids =
1191             assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap();
1192         let generated = generate_cpp_code(
1193             crate::test::TEST_PACKAGE,
1194             modified_parsed_flags.into_iter(),
1195             mode,
1196             flag_ids,
1197             allow_instrumentation,
1198         )
1199         .unwrap();
1200         let mut generated_files_map = HashMap::new();
1201         for file in generated {
1202             generated_files_map.insert(
1203                 String::from(file.path.to_str().unwrap()),
1204                 String::from_utf8(file.contents).unwrap(),
1205             );
1206         }
1207 
1208         let mut target_file_path = String::from("include/com_android_aconfig_test.h");
1209         assert!(generated_files_map.contains_key(&target_file_path));
1210         assert_eq!(
1211             None,
1212             crate::test::first_significant_code_diff(
1213                 expected_header,
1214                 generated_files_map.get(&target_file_path).unwrap()
1215             )
1216         );
1217 
1218         target_file_path = String::from("com_android_aconfig_test.cc");
1219         assert!(generated_files_map.contains_key(&target_file_path));
1220         assert_eq!(
1221             None,
1222             crate::test::first_significant_code_diff(
1223                 expected_src,
1224                 generated_files_map.get(&target_file_path).unwrap()
1225             )
1226         );
1227     }
1228 
1229     #[test]
test_generate_cpp_code_for_prod()1230     fn test_generate_cpp_code_for_prod() {
1231         let parsed_flags = crate::test::parse_test_flags();
1232         test_generate_cpp_code(
1233             parsed_flags,
1234             CodegenMode::Production,
1235             EXPORTED_PROD_HEADER_EXPECTED,
1236             PROD_SOURCE_FILE_EXPECTED,
1237             false,
1238         );
1239     }
1240 
1241     #[test]
test_generate_cpp_code_for_test()1242     fn test_generate_cpp_code_for_test() {
1243         let parsed_flags = crate::test::parse_test_flags();
1244         test_generate_cpp_code(
1245             parsed_flags,
1246             CodegenMode::Test,
1247             EXPORTED_TEST_HEADER_EXPECTED,
1248             TEST_SOURCE_FILE_EXPECTED,
1249             false,
1250         );
1251     }
1252 
1253     #[test]
test_generate_cpp_code_for_exported()1254     fn test_generate_cpp_code_for_exported() {
1255         let parsed_flags = crate::test::parse_test_flags();
1256         test_generate_cpp_code(
1257             parsed_flags,
1258             CodegenMode::Exported,
1259             EXPORTED_EXPORTED_HEADER_EXPECTED,
1260             EXPORTED_SOURCE_FILE_EXPECTED,
1261             false,
1262         );
1263     }
1264 
1265     #[test]
test_generate_cpp_code_for_force_read_only()1266     fn test_generate_cpp_code_for_force_read_only() {
1267         let parsed_flags = crate::test::parse_test_flags();
1268         test_generate_cpp_code(
1269             parsed_flags,
1270             CodegenMode::ForceReadOnly,
1271             EXPORTED_FORCE_READ_ONLY_HEADER_EXPECTED,
1272             FORCE_READ_ONLY_SOURCE_FILE_EXPECTED,
1273             false,
1274         );
1275     }
1276 
1277     #[test]
test_generate_cpp_code_for_read_only_prod()1278     fn test_generate_cpp_code_for_read_only_prod() {
1279         let parsed_flags = crate::test::parse_read_only_test_flags();
1280         test_generate_cpp_code(
1281             parsed_flags,
1282             CodegenMode::Production,
1283             READ_ONLY_EXPORTED_PROD_HEADER_EXPECTED,
1284             READ_ONLY_PROD_SOURCE_FILE_EXPECTED,
1285             false,
1286         );
1287     }
1288 }
1289