2019-10-11 17:53:28 +02:00
use std ::fs ::{ self , File } ;
2019-10-13 13:10:21 +02:00
use std ::io ::{ BufWriter , Read , Write } ;
2019-10-11 17:53:28 +02:00
use std ::process ::Command ;
2019-10-16 21:31:14 +02:00
2019-10-13 13:10:21 +02:00
use typst ::export ::pdf ::PdfExporter ;
2019-10-11 20:28:22 +02:00
use typst ::layout ::LayoutAction ;
2019-10-11 17:53:28 +02:00
use typst ::toddle ::query ::FileSystemFontProvider ;
2019-11-28 20:38:21 +01:00
use typst ::size ::{ Size , Size2D , SizeBox } ;
use typst ::style ::PageStyle ;
2019-10-13 13:10:21 +02:00
use typst ::Typesetter ;
2019-10-11 17:53:28 +02:00
2019-10-16 21:31:14 +02:00
const CACHE_DIR : & str = " tests/cache " ;
2019-10-11 17:53:28 +02:00
2019-10-11 20:28:22 +02:00
fn main ( ) {
2019-10-13 12:08:07 +02:00
let mut perfect_match = false ;
2019-10-11 20:28:22 +02:00
let mut filter = Vec ::new ( ) ;
2019-10-13 12:08:07 +02:00
2019-10-11 20:28:22 +02:00
for arg in std ::env ::args ( ) . skip ( 1 ) {
2019-10-13 12:08:07 +02:00
if arg . as_str ( ) = = " --nocapture " {
continue ;
} else if arg . as_str ( ) = = " = " {
perfect_match = true ;
} else {
2019-10-11 20:28:22 +02:00
filter . push ( arg ) ;
}
}
2019-10-11 17:53:28 +02:00
fs ::create_dir_all ( format! ( " {} /serialized " , CACHE_DIR ) ) . unwrap ( ) ;
fs ::create_dir_all ( format! ( " {} /rendered " , CACHE_DIR ) ) . unwrap ( ) ;
fs ::create_dir_all ( format! ( " {} /pdf " , CACHE_DIR ) ) . unwrap ( ) ;
for entry in fs ::read_dir ( " tests/layouts/ " ) . unwrap ( ) {
let path = entry . unwrap ( ) . path ( ) ;
2019-10-16 21:31:14 +02:00
if path . extension ( ) ! = Some ( std ::ffi ::OsStr ::new ( " typ " ) ) {
continue ;
}
2019-10-13 13:10:21 +02:00
let name = path . file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
2019-10-11 17:53:28 +02:00
2019-10-13 12:08:07 +02:00
let matches = if perfect_match {
filter . iter ( ) . any ( | pattern | name = = pattern )
} else {
filter . is_empty ( ) | | filter . iter ( ) . any ( | pattern | name . contains ( pattern ) )
} ;
if matches {
2019-10-11 20:28:22 +02:00
let mut file = File ::open ( & path ) . unwrap ( ) ;
let mut src = String ::new ( ) ;
file . read_to_string ( & mut src ) . unwrap ( ) ;
test ( name , & src ) ;
}
2019-10-11 17:53:28 +02:00
}
}
/// Create a _PDF_ with a name from the source code.
fn test ( name : & str , src : & str ) {
2019-11-06 23:03:04 +01:00
println! ( " Testing: {} . " , name ) ;
2019-10-16 21:31:14 +02:00
2019-10-11 17:53:28 +02:00
let mut typesetter = Typesetter ::new ( ) ;
2019-11-28 20:38:21 +01:00
typesetter . set_page_style ( PageStyle {
dimensions : Size2D ::with_all ( Size ::pt ( 250.0 ) ) ,
margins : SizeBox ::with_all ( Size ::pt ( 10.0 ) ) ,
} ) ;
2019-10-11 17:53:28 +02:00
let provider = FileSystemFontProvider ::from_listing ( " fonts/fonts.toml " ) . unwrap ( ) ;
typesetter . add_font_provider ( provider . clone ( ) ) ;
2019-11-28 20:38:21 +01:00
#[ cfg(not(debug_assertions)) ]
let layouts = {
use std ::time ::Instant ;
// Warmup.
let warmup_start = Instant ::now ( ) ;
typesetter . typeset ( & src ) . unwrap ( ) ;
let warmup_end = Instant ::now ( ) ;
2019-10-14 17:32:37 +02:00
2019-11-28 20:38:21 +01:00
let start = Instant ::now ( ) ;
let tree = typesetter . parse ( & src ) . unwrap ( ) ;
let mid = Instant ::now ( ) ;
let layouts = typesetter . layout ( & tree ) . unwrap ( ) ;
let end = Instant ::now ( ) ;
2019-10-31 20:26:21 +01:00
2019-11-06 23:03:04 +01:00
println! ( " - cold start: {:?} " , warmup_end - warmup_start ) ;
println! ( " - warmed up: {:?} " , end - start ) ;
println! ( " - parsing: {:?} " , mid - start ) ;
println! ( " - layouting: {:?} " , end - mid ) ;
println! ( ) ;
2019-11-28 20:38:21 +01:00
layouts
} ;
#[ cfg(debug_assertions) ]
let layouts = typesetter . typeset ( & src ) . unwrap ( ) ;
2019-10-14 17:32:37 +02:00
2019-10-11 17:53:28 +02:00
// Write the serialed layout file.
2019-11-28 20:38:21 +01:00
let path = format! ( " {} /serialized/ {} .tld " , CACHE_DIR , name ) ;
2019-10-11 17:53:28 +02:00
let mut file = File ::create ( path ) . unwrap ( ) ;
// Find all used fonts and their filenames.
let mut map = Vec ::new ( ) ;
let mut loader = typesetter . loader ( ) . borrow_mut ( ) ;
2019-10-16 21:31:14 +02:00
for layout in & layouts {
for action in & layout . actions {
if let LayoutAction ::SetFont ( index , _ ) = action {
if map . iter ( ) . find ( | ( i , _ ) | i = = index ) . is_none ( ) {
let ( _ , provider_index ) = loader . get_provider_and_index ( * index ) ;
let filename = provider . get_path ( provider_index ) . to_str ( ) . unwrap ( ) ;
map . push ( ( * index , filename ) ) ;
}
2019-10-11 17:53:28 +02:00
}
}
}
drop ( loader ) ;
// Write the font mapping into the serialization file.
writeln! ( file , " {} " , map . len ( ) ) . unwrap ( ) ;
for ( index , path ) in map {
writeln! ( file , " {} {} " , index , path ) . unwrap ( ) ;
}
2019-10-16 21:31:14 +02:00
layouts . serialize ( & mut file ) . unwrap ( ) ;
2019-10-11 17:53:28 +02:00
// Render the layout into a PNG.
Command ::new ( " python " )
. arg ( " tests/render.py " )
. arg ( name )
. spawn ( )
. expect ( " failed to run python-based renderer " ) ;
// Write the PDF file.
let path = format! ( " {} /pdf/ {} .pdf " , CACHE_DIR , name ) ;
let file = BufWriter ::new ( File ::create ( path ) . unwrap ( ) ) ;
let exporter = PdfExporter ::new ( ) ;
2019-10-16 21:31:14 +02:00
exporter . export ( & layouts , typesetter . loader ( ) , file ) . unwrap ( ) ;
}