|  | // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | use std::cell::RefCell; | 
|  | use std::collections::HashMap; | 
|  |  | 
|  | use sdk_metadata::JsonObject; | 
|  |  | 
|  | use crate::app::{Error, Result}; | 
|  | use crate::tarball::{InputTarball, OutputTarball, TarballContent}; | 
|  |  | 
|  | impl TarballContent for String { | 
|  | fn is_identical(&self, other: &String) -> Result<bool> { | 
|  | Ok(self == other) | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Clone)] | 
|  | pub struct MockInputTarball { | 
|  | files: RefCell<HashMap<String, String>>, | 
|  | } | 
|  |  | 
|  | impl MockInputTarball { | 
|  | pub fn new() -> MockInputTarball { | 
|  | MockInputTarball { files: RefCell::new(HashMap::new()) } | 
|  | } | 
|  |  | 
|  | pub fn add(&self, path: &str, content: &str) { | 
|  | assert!( | 
|  | self.files.borrow_mut().insert(path.to_owned(), content.to_owned()).is_none(), | 
|  | "Path already added: {}", | 
|  | path | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | impl InputTarball<String> for MockInputTarball { | 
|  | fn get_file<R>(&self, path: &str, reader: R) -> Result<()> | 
|  | where | 
|  | R: FnOnce(&mut String) -> Result<()>, | 
|  | { | 
|  | self.files | 
|  | .borrow_mut() | 
|  | .get_mut(path) | 
|  | .ok_or_else(|| Error::ArchiveFileNotFound { name: path.to_owned() }) | 
|  | .map(|file_path| -> Result<()> { reader(file_path) })? | 
|  | } | 
|  |  | 
|  | fn get_metadata<T: JsonObject>(&self, path: &str) -> Result<T> { | 
|  | let mut contents = String::new(); | 
|  | self.get_file(path, |value| { | 
|  | contents.push_str(value); | 
|  | Ok(()) | 
|  | })?; | 
|  | T::new(contents.as_bytes()) | 
|  | } | 
|  | } | 
|  |  | 
|  | pub struct MockOutputTarball { | 
|  | files: HashMap<String, String>, | 
|  | } | 
|  |  | 
|  | impl MockOutputTarball { | 
|  | pub fn new() -> MockOutputTarball { | 
|  | MockOutputTarball { files: HashMap::new() } | 
|  | } | 
|  |  | 
|  | pub fn assert_has_file(&self, path: &str) { | 
|  | assert!(self.files.contains_key(path), "File not found: {}", path); | 
|  | } | 
|  |  | 
|  | pub fn get_content(&self, path: &str) -> &String { | 
|  | self.assert_has_file(path); | 
|  | self.files.get(path).unwrap() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl OutputTarball<String> for MockOutputTarball { | 
|  | fn write_json<T: JsonObject>(&mut self, path: &str, content: &T) -> Result<()> { | 
|  | self.write_file(path, &mut content.to_string().unwrap()) | 
|  | } | 
|  |  | 
|  | fn write_file(&mut self, path: &str, file: &mut String) -> Result<()> { | 
|  | assert!(self.files.insert(path.to_owned(), file.clone()).is_none()); | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  | #[cfg(test)] | 
|  | mod tests { | 
|  | use super::*; | 
|  |  | 
|  | #[test] | 
|  | fn test_input_get() { | 
|  | let tarball = MockInputTarball::new(); | 
|  | let path = "foo/bar.json"; | 
|  | let content = "hello world"; | 
|  | tarball.add(path, content); | 
|  | tarball | 
|  | .get_file(path, |file_content| { | 
|  | assert_eq!(file_content, content); | 
|  | Ok(()) | 
|  | }) | 
|  | .unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_input_get_nonexistent() { | 
|  | let tarball = MockInputTarball::new(); | 
|  | let path = "foo/bar.json"; | 
|  | assert!(tarball | 
|  | .get_file(path, |_file_content| { | 
|  | assert!(false, "Should not have been called"); | 
|  | Ok(()) | 
|  | }) | 
|  | .is_err()); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | #[should_panic] | 
|  | fn test_input_double_add() { | 
|  | let tarball = MockInputTarball::new(); | 
|  | let path = "foo/bar.json"; | 
|  | let content = "hello world"; | 
|  | tarball.add(path, content); | 
|  | tarball.add(path, content); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_output_assert() { | 
|  | let mut tarball = MockOutputTarball::new(); | 
|  | let path = "foo/bar.json"; | 
|  | let mut content = "hello world".to_owned(); | 
|  | tarball.write_file(path, &mut content).unwrap(); | 
|  | tarball.assert_has_file(path); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | #[should_panic] | 
|  | fn test_output_assert_nonexistent() { | 
|  | let tarball = MockOutputTarball::new(); | 
|  | let path = "foo/bar.json"; | 
|  | tarball.assert_has_file(path); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | #[should_panic] | 
|  | fn test_output_double_write() { | 
|  | let mut tarball = MockOutputTarball::new(); | 
|  | let path = "foo/bar.json"; | 
|  | let mut content = "hello world".to_owned(); | 
|  | tarball.write_file(path, &mut content).unwrap(); | 
|  | tarball.write_file(path, &mut content).unwrap(); | 
|  | } | 
|  | } |