2021-06-18 11:27:19 -05:00
use std ::convert ::TryFrom ;
2021-08-25 14:30:27 -05:00
use std ::io ::{ BufRead , Write } ;
2021-07-07 07:19:55 -05:00
use std ::str ::FromStr ;
2021-06-18 11:27:19 -05:00
use clap ::ArgMatches ;
2021-07-16 12:45:27 -05:00
use chrono ::{ DateTime , Utc } ;
2021-07-07 10:49:29 -05:00
use regex ::Regex ;
2021-06-18 11:27:19 -05:00
2021-07-07 07:19:55 -05:00
use crate ::error ::{ Result , Error } ;
2021-07-16 12:45:27 -05:00
use crate ::database ::Database ;
2021-06-21 17:38:51 -05:00
use crate ::formatters ::Formatter ;
2021-07-01 23:42:59 -05:00
use crate ::timeparse ::parse_time ;
2021-07-07 10:49:29 -05:00
use crate ::regex ::parse_regex ;
2021-08-11 17:54:37 -05:00
use crate ::old ::{ entries_or_warning , time_or_warning , warn_if_needed } ;
2021-08-25 14:30:27 -05:00
use crate ::io ::Streams ;
2021-06-18 11:27:19 -05:00
2021-08-25 14:30:27 -05:00
use super ::{ Command , Facts } ;
2021-07-07 07:19:55 -05:00
// ----------------------------------------------------------------
// Things that are general to all commands that display in some way
// ----------------------------------------------------------------
pub enum Sheet {
All ,
Full ,
Sheet ( String ) ,
}
impl FromStr for Sheet {
type Err = Error ;
fn from_str ( name : & str ) -> Result < Sheet > {
Ok ( match name {
" all " = > Sheet ::All ,
" full " = > Sheet ::Full ,
name = > Sheet ::Sheet ( name . into ( ) ) ,
} )
}
}
2021-08-02 19:13:11 -05:00
#[ allow(clippy::too_many_arguments) ]
2021-08-25 14:30:27 -05:00
pub fn entries_for_display < D , I , O , E > (
2021-07-07 07:19:55 -05:00
start : Option < DateTime < Utc > > , end : Option < DateTime < Utc > > ,
2021-08-25 14:30:27 -05:00
sheet : Option < Sheet > , streams : & mut Streams < D , I , O , E > ,
2021-07-07 10:49:29 -05:00
format : Formatter , ids : bool , grep : Option < Regex > ,
2021-08-25 14:30:27 -05:00
facts : & Facts ,
2021-07-07 07:19:55 -05:00
) -> Result < ( ) >
where
D : Database ,
2021-08-25 14:30:27 -05:00
I : BufRead ,
2021-07-07 07:19:55 -05:00
O : Write ,
E : Write ,
{
2021-08-25 14:30:27 -05:00
let start = start . map ( | s | time_or_warning ( s , & streams . db ) ) . transpose ( ) ? . map ( | s | s . 0 ) ;
let end = end . map ( | e | time_or_warning ( e , & streams . db ) ) . transpose ( ) ? . map ( | e | e . 0 ) ;
2021-08-11 17:54:37 -05:00
2021-07-07 10:49:29 -05:00
let mut entries = match sheet {
2021-08-25 14:30:27 -05:00
Some ( Sheet ::All ) = > streams . db . entries_all_visible ( start , end ) ? ,
Some ( Sheet ::Full ) = > streams . db . entries_full ( start , end ) ? ,
Some ( Sheet ::Sheet ( name ) ) = > streams . db . entries_by_sheet ( & name , start , end ) ? ,
2021-07-07 07:19:55 -05:00
None = > {
2022-05-07 22:36:03 -05:00
let current_sheet = streams . db . current_sheet ( ) ? ;
2021-07-07 07:19:55 -05:00
2021-08-25 14:30:27 -05:00
streams . db . entries_by_sheet ( & current_sheet , start , end ) ?
2021-07-07 07:19:55 -05:00
}
} ;
2021-07-07 10:49:29 -05:00
if let Some ( re ) = grep {
2022-05-06 09:04:36 -05:00
entries . retain ( | e | re . is_match ( & e . note . clone ( ) . unwrap_or_default ( ) ) ) ;
2021-07-07 10:49:29 -05:00
}
2021-08-25 14:30:27 -05:00
let ( entries , needs_warning ) = entries_or_warning ( entries , & streams . db ) ? ;
2021-07-07 07:19:55 -05:00
format . print_formatted (
entries ,
2021-08-25 14:30:27 -05:00
& mut streams . out ,
2021-09-06 20:08:53 -05:00
& mut streams . err ,
2021-08-25 14:43:50 -05:00
facts ,
2021-07-07 07:19:55 -05:00
ids ,
) ? ;
2021-08-25 14:30:27 -05:00
warn_if_needed ( & mut streams . err , needs_warning , & facts . env ) ? ;
2021-07-07 07:19:55 -05:00
Ok ( ( ) )
}
// ------------------------------------
// The actual implementation of display
// ------------------------------------
2021-06-21 19:54:10 -05:00
2021-06-29 12:04:54 -05:00
#[ derive(Default) ]
2021-06-18 11:27:19 -05:00
pub struct Args {
2021-06-21 17:38:51 -05:00
ids : bool ,
2021-06-24 00:07:52 -05:00
start : Option < DateTime < Utc > > ,
end : Option < DateTime < Utc > > ,
2021-08-19 20:50:34 -05:00
format : Option < Formatter > ,
2021-07-07 10:49:29 -05:00
grep : Option < Regex > ,
2021-06-21 19:54:10 -05:00
sheet : Option < Sheet > ,
2021-06-18 11:27:19 -05:00
}
impl < ' a > TryFrom < & ' a ArgMatches < ' a > > for Args {
2021-07-07 07:19:55 -05:00
type Error = Error ;
2021-06-18 11:27:19 -05:00
2021-07-07 07:19:55 -05:00
fn try_from ( matches : & ' a ArgMatches ) -> Result < Args > {
2021-06-21 17:38:51 -05:00
Ok ( Args {
ids : matches . is_present ( " ids " ) ,
2021-12-13 14:20:56 -06:00
start : matches . value_of ( " start " ) . map ( parse_time ) . transpose ( ) ? ,
end : matches . value_of ( " end " ) . map ( parse_time ) . transpose ( ) ? ,
2021-08-19 20:50:34 -05:00
format : matches . value_of ( " format " ) . map ( | v | v . parse ( ) ) . transpose ( ) ? ,
2021-07-07 10:49:29 -05:00
grep : matches . value_of ( " grep " ) . map ( parse_regex ) . transpose ( ) ? ,
2021-06-21 19:54:10 -05:00
sheet : matches . value_of ( " sheet " ) . map ( | s | s . parse ( ) ) . transpose ( ) ? ,
2021-06-21 17:38:51 -05:00
} )
2021-06-18 11:27:19 -05:00
}
}
2021-06-29 18:20:51 -05:00
pub struct DisplayCommand { }
2021-06-18 11:27:19 -05:00
impl < ' a > Command < ' a > for DisplayCommand {
type Args = Args ;
2021-08-25 14:30:27 -05:00
fn handle < D , I , O , E > ( args : Self ::Args , streams : & mut Streams < D , I , O , E > , facts : & Facts ) -> Result < ( ) >
2021-06-18 11:27:19 -05:00
where
D : Database ,
2021-08-25 14:30:27 -05:00
I : BufRead ,
2021-06-29 12:02:33 -05:00
O : Write ,
E : Write ,
2021-06-18 11:27:19 -05:00
{
2021-08-19 20:50:34 -05:00
entries_for_display (
args . start ,
args . end ,
args . sheet ,
2021-08-25 14:30:27 -05:00
streams ,
2022-08-29 18:45:45 -05:00
args . format . unwrap_or_else ( | | facts . config . commands . display . default_formatter . as_ref ( ) . unwrap_or ( & facts . config . default_formatter ) . clone ( ) ) ,
2021-08-19 20:50:34 -05:00
args . ids ,
args . grep ,
2021-08-25 14:30:27 -05:00
facts
2021-08-19 20:50:34 -05:00
)
2021-06-18 11:27:19 -05:00
}
}
2021-06-29 12:04:54 -05:00
#[ cfg(test) ]
mod tests {
2021-07-06 22:52:20 -05:00
use chrono ::TimeZone ;
2022-08-01 09:04:22 -05:00
use pretty_assertions ::{ assert_eq , assert_str_eq } ;
2021-06-29 12:04:54 -05:00
use crate ::database ::SqliteDatabase ;
2022-08-29 18:45:45 -05:00
use crate ::config ::{ Config , CommandsSettings , BaseCommandSettings } ;
2021-06-29 12:04:54 -05:00
2021-07-06 22:52:20 -05:00
use super ::* ;
2021-06-29 12:04:54 -05:00
#[ test ]
fn display_as_local_time_if_previous_version ( ) {
2021-08-11 17:54:37 -05:00
std ::env ::set_var ( " TZ " , " CST+6 " ) ;
2021-08-25 14:30:27 -05:00
2021-06-29 12:04:54 -05:00
let args = Default ::default ( ) ;
2021-08-25 14:30:27 -05:00
let mut streams = Streams ::fake ( b " " ) . with_db (
SqliteDatabase ::from_path ( " assets/test_old_db.db " ) . unwrap ( )
) ;
let facts = Facts ::new ( ) ;
2021-06-29 12:04:54 -05:00
2021-08-25 14:30:27 -05:00
DisplayCommand ::handle ( args , & mut streams , & facts ) . unwrap ( ) ;
2021-06-29 12:04:54 -05:00
2022-07-19 05:38:37 -05:00
assert_eq! ( & String ::from_utf8_lossy ( & streams . out ) , " Timesheet: default
2021-06-29 12:04:54 -05:00
Day Start End Duration Notes
Tue Jun 29 , 2021 06 :26 :49 - 07 :26 :52 1 :00 :03 lets do some rust
1 :00 :03
2021-07-15 11:17:50 -05:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2021-06-29 12:04:54 -05:00
Total 1 :00 :03
2022-07-19 05:38:37 -05:00
" );
2021-06-29 12:04:54 -05:00
assert_eq! (
2021-08-25 14:30:27 -05:00
String ::from_utf8_lossy ( & streams . err ) ,
2022-08-29 18:03:11 -05:00
" [WARNING] You are using the old timetrap format, it is advised that you update your database using t migrate. To supress this warning set TIEMPO_SUPRESS_TIMETRAP_WARNING=1 \n "
2021-06-29 12:04:54 -05:00
) ;
}
2021-06-30 19:20:10 -05:00
#[ test ]
fn filter_by_start ( ) {
let args = Args {
2021-08-19 20:50:34 -05:00
format : Some ( Formatter ::Csv ) ,
2021-06-30 19:20:10 -05:00
start : Some ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 5 , 0 ) ) ,
.. Default ::default ( )
} ;
2021-08-25 14:30:27 -05:00
let mut streams = Streams ::fake ( b " " ) ;
let facts = Facts ::new ( ) ;
2021-06-30 19:20:10 -05:00
2021-12-13 14:20:56 -06:00
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 0 , 0 ) , None , Some ( " hola " . into ( ) ) , " default " ) . unwrap ( ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 10 , 0 ) , None , Some ( " hola " . into ( ) ) , " default " ) . unwrap ( ) ;
2021-06-30 19:20:10 -05:00
2021-08-25 14:30:27 -05:00
DisplayCommand ::handle ( args , & mut streams , & facts ) . unwrap ( ) ;
2021-06-30 19:20:10 -05:00
2022-07-19 05:38:37 -05:00
assert_eq! ( & String ::from_utf8_lossy ( & streams . out ) , " start,end,note,sheet
2021-08-11 17:54:37 -05:00
2021 - 06 - 30 T10 :10 :00.000000 Z , , hola , default
2022-07-19 05:38:37 -05:00
" );
2021-06-30 19:20:10 -05:00
assert_eq! (
2021-08-25 14:30:27 -05:00
String ::from_utf8_lossy ( & streams . err ) ,
2021-06-30 19:20:10 -05:00
String ::new ( ) ,
) ;
}
#[ test ]
fn filter_by_match ( ) {
2021-08-25 14:30:27 -05:00
let mut streams = Streams ::fake ( b " " ) ;
let facts = Facts ::new ( ) ;
2021-07-07 10:49:29 -05:00
2021-12-13 14:20:56 -06:00
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 0 , 0 ) , None , Some ( " hola " . into ( ) ) , " default " ) . unwrap ( ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 10 , 0 ) , None , Some ( " adios " . into ( ) ) , " default " ) . unwrap ( ) ;
2021-07-07 10:49:29 -05:00
2021-08-25 14:30:27 -05:00
entries_for_display ( None , None , None , & mut streams , Formatter ::Csv , true , Some ( " io " . parse ( ) . unwrap ( ) ) , & facts ) . unwrap ( ) ;
2021-07-07 10:49:29 -05:00
2022-07-19 05:38:37 -05:00
assert_eq! ( & String ::from_utf8_lossy ( & streams . out ) , " id,start,end,note,sheet
2021-08-11 17:54:37 -05:00
2 , 2021 - 06 - 30 T10 :10 :00.000000 Z , , adios , default
2022-07-19 05:38:37 -05:00
" );
2021-07-07 10:49:29 -05:00
assert_eq! (
2021-08-25 14:30:27 -05:00
String ::from_utf8_lossy ( & streams . err ) ,
2021-07-07 10:49:29 -05:00
String ::new ( ) ,
) ;
2021-06-30 19:20:10 -05:00
}
2021-07-16 17:52:33 -05:00
#[ test ]
fn entries_are_grouped_despite_database ( ) {
let args = Args {
sheet : Some ( Sheet ::All ) ,
.. Default ::default ( )
} ;
2021-08-25 14:30:27 -05:00
let mut streams = Streams ::fake ( b " " ) ;
let facts = Facts ::new ( ) ;
2021-08-11 17:54:37 -05:00
std ::env ::set_var ( " TZ " , " CST+6 " ) ;
2021-07-16 17:52:33 -05:00
2021-12-13 14:20:56 -06:00
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 0 , 0 ) , Some ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 11 , 0 , 0 ) ) , None , " sheet1 " ) . unwrap ( ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 11 , 0 , 0 ) , Some ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 12 , 0 , 0 ) ) , None , " sheet2 " ) . unwrap ( ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 12 , 0 , 0 ) , Some ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 13 , 0 , 0 ) ) , None , " sheet1 " ) . unwrap ( ) ;
2021-07-16 17:52:33 -05:00
2021-08-25 14:30:27 -05:00
DisplayCommand ::handle ( args , & mut streams , & facts ) . unwrap ( ) ;
2021-07-16 17:52:33 -05:00
2022-08-01 09:04:22 -05:00
assert_str_eq! ( & String ::from_utf8_lossy ( & streams . out ) , " Timesheet: sheet1
2021-07-16 17:52:33 -05:00
Day Start End Duration Notes
2021-08-11 17:54:37 -05:00
Wed Jun 30 , 2021 04 :00 :00 - 05 :00 :00 1 :00 :00
06 :00 :00 - 07 :00 :00 1 :00 :00
2021-07-16 17:52:33 -05:00
2 :00 :00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total 2 :00 :00
Timesheet : sheet2
Day Start End Duration Notes
2021-08-11 17:54:37 -05:00
Wed Jun 30 , 2021 05 :00 :00 - 06 :00 :00 1 :00 :00
2021-07-16 17:52:33 -05:00
1 :00 :00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total 1 :00 :00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Grand total 3 :00 :00
2022-07-19 05:38:37 -05:00
" );
2021-07-16 17:52:33 -05:00
}
#[ test ]
fn entries_are_grouped_despite_database_full ( ) {
let args = Args {
sheet : Some ( Sheet ::Full ) ,
.. Default ::default ( )
} ;
2021-08-25 14:30:27 -05:00
let mut streams = Streams ::fake ( b " " ) ;
let facts = Facts ::new ( ) ;
2021-08-11 17:54:37 -05:00
std ::env ::set_var ( " TZ " , " CST+6 " ) ;
2021-07-16 17:52:33 -05:00
2021-12-13 14:20:56 -06:00
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 0 , 0 ) , Some ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 11 , 0 , 0 ) ) , None , " sheet1 " ) . unwrap ( ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 11 , 0 , 0 ) , Some ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 12 , 0 , 0 ) ) , None , " _sheet2 " ) . unwrap ( ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 12 , 0 , 0 ) , Some ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 13 , 0 , 0 ) ) , None , " sheet1 " ) . unwrap ( ) ;
2021-07-16 17:52:33 -05:00
2021-08-25 14:30:27 -05:00
DisplayCommand ::handle ( args , & mut streams , & facts ) . unwrap ( ) ;
2021-07-16 17:52:33 -05:00
2022-07-19 05:38:37 -05:00
assert_eq! ( & String ::from_utf8_lossy ( & streams . out ) , " \
2021-07-16 17:52:33 -05:00
Timesheet : _sheet2
Day Start End Duration Notes
2021-08-11 17:54:37 -05:00
Wed Jun 30 , 2021 05 :00 :00 - 06 :00 :00 1 :00 :00
2021-07-16 17:52:33 -05:00
1 :00 :00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total 1 :00 :00
Timesheet : sheet1
Day Start End Duration Notes
2021-08-11 17:54:37 -05:00
Wed Jun 30 , 2021 04 :00 :00 - 05 :00 :00 1 :00 :00
06 :00 :00 - 07 :00 :00 1 :00 :00
2021-07-16 17:52:33 -05:00
2 :00 :00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total 2 :00 :00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Grand total 3 :00 :00
2022-07-19 05:38:37 -05:00
" );
2021-07-16 17:52:33 -05:00
}
2021-08-11 17:54:37 -05:00
#[ test ]
fn filter_old_database ( ) {
std ::env ::set_var ( " TZ " , " CST+6 " ) ;
let args = Args {
2021-08-19 20:50:34 -05:00
format : Some ( Formatter ::Csv ) ,
2021-08-11 17:54:37 -05:00
start : Some ( Utc . ymd ( 2021 , 6 , 29 ) . and_hms ( 12 , 0 , 0 ) ) ,
end : Some ( Utc . ymd ( 2021 , 6 , 29 ) . and_hms ( 13 , 0 , 0 ) ) ,
.. Default ::default ( )
} ;
2021-08-25 14:30:27 -05:00
let mut streams = Streams ::fake ( b " " ) . with_db (
SqliteDatabase ::from_path ( " assets/test_old_db.db " ) . unwrap ( )
) ;
let facts = Facts ::new ( ) ;
2021-08-11 17:54:37 -05:00
// item in database:
// start: 2021-06-29 06:26:49.580565
// end: 2021-06-29 07:26:52.816747
2021-08-25 14:30:27 -05:00
DisplayCommand ::handle ( args , & mut streams , & facts ) . unwrap ( ) ;
2021-08-11 17:54:37 -05:00
2022-07-19 05:38:37 -05:00
assert_eq! ( & String ::from_utf8_lossy ( & streams . out ) , " start,end,note,sheet
2021-08-11 17:54:37 -05:00
2021 - 06 - 29 T12 :26 :49.580565 Z , 2021 - 06 - 29 T13 :26 :52.816747 Z , lets do some rust , default
2022-07-19 05:38:37 -05:00
" );
2021-08-11 17:54:37 -05:00
assert_eq! (
2021-08-25 14:30:27 -05:00
String ::from_utf8_lossy ( & streams . err ) ,
2022-08-29 18:03:11 -05:00
" [WARNING] You are using the old timetrap format, it is advised that you update your database using t migrate. To supress this warning set TIEMPO_SUPRESS_TIMETRAP_WARNING=1 \n "
2021-08-11 17:54:37 -05:00
) ;
}
2021-08-19 20:50:34 -05:00
#[ test ]
fn respect_default_formatter ( ) {
std ::env ::set_var ( " TZ " , " CST+6 " ) ;
let args = Default ::default ( ) ;
2021-08-25 14:30:27 -05:00
let mut streams = Streams ::fake ( b " " ) ;
let facts = Facts ::new ( ) . with_config ( Config {
2021-08-19 20:50:34 -05:00
default_formatter : Formatter ::Ids ,
.. Default ::default ( )
2021-08-25 14:30:27 -05:00
} ) ;
2021-08-19 20:50:34 -05:00
2021-12-13 14:20:56 -06:00
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 0 , 0 ) , None , Some ( " hola " . into ( ) ) , " default " ) . unwrap ( ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 10 , 0 ) , None , Some ( " hola " . into ( ) ) , " default " ) . unwrap ( ) ;
2021-08-19 20:50:34 -05:00
2021-08-25 14:30:27 -05:00
DisplayCommand ::handle ( args , & mut streams , & facts ) . unwrap ( ) ;
2021-08-19 20:50:34 -05:00
2021-08-25 14:30:27 -05:00
assert_eq! ( & String ::from_utf8_lossy ( & streams . out ) , " 1 2 \n " ) ;
assert_eq! ( String ::from_utf8_lossy ( & streams . err ) , " " ) ;
2021-08-19 20:50:34 -05:00
}
2022-08-29 18:45:45 -05:00
#[ test ]
fn respect_command_default_formatter ( ) {
std ::env ::set_var ( " TZ " , " CST+6 " ) ;
let args = Default ::default ( ) ;
let mut streams = Streams ::fake ( b " " ) ;
let facts = Facts ::new ( ) . with_config ( Config {
commands : CommandsSettings {
display : BaseCommandSettings {
default_formatter : Some ( Formatter ::Ids ) ,
} ,
.. Default ::default ( )
} ,
.. Default ::default ( )
} ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 0 , 0 ) , None , Some ( " hola " . into ( ) ) , " default " ) . unwrap ( ) ;
streams . db . entry_insert ( Utc . ymd ( 2021 , 6 , 30 ) . and_hms ( 10 , 10 , 0 ) , None , Some ( " hola " . into ( ) ) , " default " ) . unwrap ( ) ;
DisplayCommand ::handle ( args , & mut streams , & facts ) . unwrap ( ) ;
assert_eq! ( & String ::from_utf8_lossy ( & streams . out ) , " 1 2 \n " ) ;
assert_eq! ( String ::from_utf8_lossy ( & streams . err ) , " " ) ;
}
2021-06-29 12:04:54 -05:00
}