Test Writer

Краен срок
18.12.2018 17:00

Срокът за предаване на решения е отминал

Ако сте започнали домашно 3, може да си задавате въпроса "а как да тествам, че logger-а пише във файл?" Отговора е: чрез нещо друго, което имплементира Write.

Бихте могли да подадете Vec<u8>, например, но как ще го извадите после, за да проверите какво е било записано в него? Всичко, което приема Write структура, ще иска да я консумира, или поне да вземе mutable reference, а това се усложнява, когато искате да тествате logger-и, които споделят един такъв writer.

Очакваме да напишете TestWriter, който да е Write, и да може да се клонира със споделяне на вътрешния буфер. Дефиницията би изглеждала нещо такова:

use std::io::Write;

pub struct TestWriter {
    /// Каквито полета ви трябват, но вероятно нещо, което обвива Vec<u8>
}

impl TestWriter {
    /// Конструира нов TestWriter с празен контейнер за байтове.
    ///
    pub fn new() -> Self {
        unimplemented!()
    }

    /// Консумира структурата и връща Vec с байтове, в който се съдържа каквото е било писано
    /// чрез методите на `Write` trait-а.
    ///
    pub fn into_inner(self) -> Vec<u8> {
        unimplemented!()
    }

    /// Този метод съществува по-скоро за демонстрация как бихте могли удобно да използвате този
    /// тип, без да жонглирате байтове. Няма да се тества, ако решите да го махнете или пренапишете
    /// някак.
    ///
    pub fn into_string(self) -> String {
        String::from_utf8(self.into_inner()).unwrap()
    }
}

impl Write for TestWriter {
    /// Подходяща имплементация на Write
}

impl Clone for TestWriter {
    /// Подходяща имплементация на Clone
}

Употребата в един примерен тест за нещо, което има нужда от writer, би могла да изглежда така:

let out = TestWriter::new();
{
    let thing = ThingThatWeAreTesting::new(out.clone());
    thing.wake_up_neo();
    thing.the_matrix_has_you();
    thing.follow_the_white_rabbit();
}

assert_eq!(out.into_string(), "Knock, knock, Neo");

Решения

Андрей
  • Непроверено
  • 1 успешни тест(а)
  • 0 неуспешни тест(а)
Андрей
use std::rc::Rc;
use std::cell::RefCell;
use std::io::{self, Write};
#[derive(Clone)]
pub struct TestWriter {
storage: Rc<RefCell<Vec<u8>>>,
}
impl TestWriter {
pub fn new() -> Self {
TestWriter { storage: Rc::new(RefCell::new(Vec::new())) }
}
pub fn into_inner(self) -> Vec<u8> {
Rc::try_unwrap(self.storage).ok().unwrap().into_inner()
}
pub fn into_string(self) -> String {
String::from_utf8(self.into_inner()).unwrap()
}
}
impl Write for TestWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.storage.borrow_mut().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.storage.borrow_mut().flush()
}
}
Антонио Миндов
  • Непроверено
  • 1 успешни тест(а)
  • 0 неуспешни тест(а)
Антонио Миндов
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
use std::io;
pub struct TestWriter {
buffer: Rc<RefCell<Vec<u8>>>
}
impl TestWriter {
pub fn new() -> Self {
TestWriter {buffer: Rc::new(RefCell::new(Vec::new()))}
}
pub fn into_inner(self) -> Vec<u8> {
if let Ok(buffer) = Rc::try_unwrap(self.buffer) {
return buffer.into_inner();
}
return Vec::new();
}
pub fn into_string(self) -> String {
String::from_utf8(self.into_inner()).unwrap()
}
}
impl Write for TestWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.borrow_mut().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.buffer.borrow_mut().flush()
}
}
impl Clone for TestWriter {
fn clone(&self) -> Self {
TestWriter {buffer: Rc::clone(&self.buffer)}
}
}
Николай Данаилов
  • Непроверено
  • 1 успешни тест(а)
  • 0 неуспешни тест(а)
Николай Данаилов
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Default)]
pub struct TestWriter {
/// Каквито полета ви трябват, но вероятно нещо, което обвива Vec<u8>
data: Rc<RefCell<Vec<u8>>>
}
impl TestWriter {
/// Конструира нов TestWriter с празен контейнер за байтове.
///
pub fn new() -> Self {
TestWriter {
data: Rc::new(RefCell::new(vec![]))
}
}
/// Консумира структурата и връща Vec с байтове, в който се съдържа каквото е било писано
/// чрез методите на `Write` trait-а.
///
pub fn into_inner(self) -> Vec<u8> {
Rc::try_unwrap(self.data).unwrap().into_inner()
}
/// Този метод съществува по-скоро за демонстрация как бихте могли удобно да използвате този
/// тип, без да жонглирате байтове. Няма да се тества, ако решите да го махнете или пренапишете
/// някак.
///
pub fn into_string(self) -> String {
String::from_utf8(self.into_inner()).unwrap()
}
}
impl Write for TestWriter {
/// Подходяща имплементация на Write
fn write(&mut self, bytes: &[u8]) -> std::result::Result<usize, std::io::Error> {
let mut borrowed_data = self.data.borrow_mut();
for byte in bytes {
borrowed_data.push(*byte);
}
Ok(bytes.len())
}
fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
Ok(())
}
}
impl Clone for TestWriter {
/// Подходяща имплементация на Clone
fn clone(&self) -> Self {
TestWriter {
data: self.data.clone()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn writes() {
let mut writer = TestWriter::new();
writer.write(&[41, 52, 42]);
assert_eq!(writer.into_string(), ")4*");
}
}
Даниела Русева
  • Непроверено
  • 1 успешни тест(а)
  • 0 неуспешни тест(а)
Даниела Русева
use std::io;
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
pub struct TestWriter {
buffer: Rc<RefCell<Vec<u8>>>,
}
impl TestWriter {
pub fn new() -> Self {
Self { buffer: Rc::new(RefCell::new(Vec::new())) }
}
pub fn into_inner(self) -> Vec<u8> {
self.buffer.borrow().to_vec()
}
pub fn into_string(self) -> String {
String::from_utf8(self.into_inner()).unwrap()
}
}
impl Write for TestWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.borrow_mut().extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
impl Clone for TestWriter {
fn clone(&self) -> TestWriter {
TestWriter { buffer: (Rc::clone(&self.buffer)) }
}
}
Гергана Грудева
  • Непроверено
  • 0 успешни тест(а)
  • 1 неуспешни тест(а)
Гергана Грудева
use std::io::Write;
use std::rc::Rc;
pub struct TestWriter {
buffer: Rc<Vec<u8>>
}
impl TestWriter {
pub fn new() -> Self {
TestWriter{ buffer: Rc::new(Vec::new())}
}
pub fn into_inner(self) -> Vec<u8> {
self.buffer.to_vec()
}
pub fn into_string(self) -> String {
String::from_utf8(self.into_inner()).unwrap()
}
}
impl Write for TestWriter {
fn write(&mut self,buff: &[u8]) -> Result<usize, std::io::Error> {
(*Rc::make_mut(&mut self.buffer)).write(buff)
}
fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
(*Rc::make_mut(&mut self.buffer)).flush()
}
}
impl Clone for TestWriter {
fn clone(&self) -> Self {
TestWriter{ buffer: self.buffer.clone() }
}
}
Димитър Михайлов
  • Непроверено
  • 0 успешни тест(а)
  • 1 неуспешни тест(а)
Димитър Михайлов
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
use std::result::Result;
use std::io::Error;
pub struct TestWriter {
/// Каквито полета ви трябват, но вероятно нещо, което обвива Vec<u8>
buffer: Rc<RefCell<Vec<u8>>>
}
pub struct ThingThatWeAreTesting<W: Write> {
out: Rc<RefCell<W>>
}
impl<W: Write> ThingThatWeAreTesting<W> {
pub fn new(out: W) -> Self {
return ThingThatWeAreTesting { out: Rc::new(RefCell::new(out)) };
}
pub fn wake_up_neo(&self) {
self.out.borrow_mut().write(b"Knock, ").unwrap();
}
pub fn the_matrix_has_you(&self) {
self.out.borrow_mut().write(b"knock, ").unwrap();
}
pub fn follow_the_white_rabbit(&self) {
self.out.borrow_mut().write(b"Neo").unwrap();
}
}
impl TestWriter {
/// Конструира нов TestWriter с празен контейнер за байтове.
///
pub fn new() -> Self {
return TestWriter { buffer: Rc::new(RefCell::new(Vec::new()))}
}
/// Консумира структурата и връща Vec с байтове, в който се съдържа каквото е било писано
/// чрез методите на `Write` trait-а.
///
pub fn into_inner(self) -> Vec<u8> {
return self.buffer.borrow_mut().clone();
}
/// Този метод съществува по-скоро за демонстрация как бихте могли удобно да използвате този
/// тип, без да жонглирате байтове. Няма да се тества, ако решите да го махнете или пренапишете
/// някак.
///
pub fn into_string(self) -> String {
String::from_utf8(self.into_inner()).unwrap()
}
}
impl Write for TestWriter {
fn write(&mut self, text: &[u8]) -> Result<usize, Error> {
for &byte in text {
self.buffer.borrow_mut().push(byte);
}
return Ok(self.buffer.borrow_mut().len());
}
fn flush(&mut self) -> Result<(), Error> {
return Ok(());
}
}
impl Clone for TestWriter {
fn clone(&self) -> Self {
return TestWriter { buffer: Rc::clone(&self.buffer)}
}
}
fn main() {
let out = TestWriter::new();
{
let thing = ThingThatWeAreTesting::new(out.clone());
thing.wake_up_neo();
thing.the_matrix_has_you();
thing.follow_the_white_rabbit();
}
assert_eq!(out.into_string(), "Knock, knock, Neo");
}
Християн Захариев
  • Непроверено
  • 0 успешни тест(а)
  • 1 неуспешни тест(а)
Християн Захариев
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
use std::result::Result;
use std::io::Error;
pub struct ThingThatWeAreTesting<W: Write> {
out: Rc<RefCell<W>>
}
pub struct TestWriter {
values: Rc<RefCell<Vec<u8>>>
}
impl TestWriter {
pub fn new() -> Self {
TestWriter { values: Rc::new(RefCell::new(vec![]))}
}
pub fn into_inner(self) -> Vec<u8> {
self.values.borrow_mut().clone()
}
pub fn into_string(self) -> String {
String::from_utf8(self.into_inner()).unwrap()
}
}
impl Write for TestWriter {
fn write(&mut self, text: &[u8]) -> Result<usize, Error> {
&text.iter().for_each(|b| self.values.borrow_mut().push(b.to_owned()));
Ok(self.values.borrow_mut().len())
}
fn flush(&mut self) -> Result<(), Error> {
Ok(())
}
}
impl Clone for TestWriter {
fn clone(&self) -> Self {
return TestWriter { values: Rc::clone(&self.values) }
}
}
impl<W: Write> ThingThatWeAreTesting<W> {
pub fn new(out: W) -> Self {
ThingThatWeAreTesting { out: Rc::new(RefCell::new(out)) }
}
pub fn wake_up_neo(&self) {
self.out.borrow_mut().write(b"Knock,").unwrap();
}
pub fn the_matrix_has_you(&self) {
self.out.borrow_mut().write(b" knock,").unwrap();
}
pub fn follow_the_white_rabbit(&self) {
self.out.borrow_mut().write(b" Neo").unwrap();
}
}
fn main() {
let out = TestWriter::new();
{
let thing = ThingThatWeAreTesting::new(out.clone());
thing.wake_up_neo();
thing.the_matrix_has_you();
thing.follow_the_white_rabbit();
}
assert_eq!(out.into_string(), "Knock, knock, Neo");
}