2020-07-21 17:22:31 -04:00
|
|
|
|
//! Build-in filters
|
|
|
|
|
|
2020-07-14 18:31:07 -04:00
|
|
|
|
use std::fmt;
|
2020-07-21 17:22:31 -04:00
|
|
|
|
use std::ptr;
|
2020-07-14 18:31:07 -04:00
|
|
|
|
|
|
|
|
|
use super::{Buffer, Render, RenderError};
|
|
|
|
|
|
2020-12-20 07:20:52 -05:00
|
|
|
|
/// Helper struct for 'display' filter
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub struct Display<'a, T: ?Sized>(&'a T);
|
2020-07-14 18:31:07 -04:00
|
|
|
|
|
2020-12-28 08:33:49 -05:00
|
|
|
|
impl<'a, T: fmt::Display + ?Sized> Render for Display<'a, T> {
|
2020-07-14 18:31:07 -04:00
|
|
|
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
use fmt::Write;
|
|
|
|
|
|
|
|
|
|
write!(b, "{}", self.0).map_err(|e| RenderError::from(e))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// render using `std::fmt::Display` trait
|
2020-12-20 07:13:45 -05:00
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// filename: <%= filename.display() | disp %>
|
|
|
|
|
/// ```
|
2020-07-14 18:31:07 -04:00
|
|
|
|
#[inline]
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub fn disp<T: fmt::Display + ?Sized>(expr: &T) -> Display<T> {
|
2020-07-14 18:31:07 -04:00
|
|
|
|
Display(expr)
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-20 07:20:52 -05:00
|
|
|
|
/// Helper struct for 'dbg' filter
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub struct Debug<'a, T: ?Sized>(&'a T);
|
2020-07-14 18:31:07 -04:00
|
|
|
|
|
2020-12-28 08:33:49 -05:00
|
|
|
|
impl<'a, T: fmt::Debug + ?Sized> Render for Debug<'a, T> {
|
2020-07-14 18:31:07 -04:00
|
|
|
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
use fmt::Write;
|
|
|
|
|
|
|
|
|
|
write!(b, "{:?}", self.0).map_err(|e| RenderError::from(e))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// render using `std::fmt::Debug` trait
|
2020-12-20 07:13:45 -05:00
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// The following examples produce exactly same results, but former is a bit faster
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// table content: <%= table | dbg %>
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
2020-12-28 07:28:53 -05:00
|
|
|
|
/// table content: <%= format!("{:?}", table) %>
|
2020-12-20 07:13:45 -05:00
|
|
|
|
/// ```
|
2020-07-14 18:31:07 -04:00
|
|
|
|
#[inline]
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub fn dbg<T: fmt::Debug + ?Sized>(expr: &T) -> Debug<T> {
|
2020-07-14 18:31:07 -04:00
|
|
|
|
Debug(expr)
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-20 07:20:52 -05:00
|
|
|
|
/// Helper struct for 'upper' filter
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub struct Upper<'a, T: ?Sized>(&'a T);
|
2020-07-14 18:31:07 -04:00
|
|
|
|
|
2020-12-28 08:33:49 -05:00
|
|
|
|
impl<'a, T: Render + ?Sized> Render for Upper<'a, T> {
|
2020-07-14 18:31:07 -04:00
|
|
|
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
let old_len = b.len();
|
|
|
|
|
self.0.render(b)?;
|
|
|
|
|
|
2020-12-28 15:19:12 -05:00
|
|
|
|
let content = b.as_str().get(old_len..).ok_or(RenderError::BufSize)?;
|
2020-12-19 06:38:55 -05:00
|
|
|
|
let s = content.to_uppercase();
|
2020-12-17 02:24:57 -05:00
|
|
|
|
unsafe { b._set_len(old_len) };
|
2020-07-14 18:31:07 -04:00
|
|
|
|
b.push_str(&*s);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// convert the rendered contents to uppercase
|
2020-12-20 07:13:45 -05:00
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// <%= "tschüß" | upper %>
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// result:
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// TSCHÜSS
|
|
|
|
|
/// ```
|
2020-07-14 18:31:07 -04:00
|
|
|
|
#[inline]
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub fn upper<T: Render + ?Sized>(expr: &T) -> Upper<T> {
|
2020-07-14 18:31:07 -04:00
|
|
|
|
Upper(expr)
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-20 07:20:52 -05:00
|
|
|
|
/// Helper struct for 'lower' filter
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub struct Lower<'a, T: ?Sized>(&'a T);
|
2020-07-14 18:31:07 -04:00
|
|
|
|
|
2020-12-28 08:33:49 -05:00
|
|
|
|
impl<'a, T: Render + ?Sized> Render for Lower<'a, T> {
|
2020-07-14 18:31:07 -04:00
|
|
|
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
let old_len = b.len();
|
|
|
|
|
self.0.render(b)?;
|
|
|
|
|
|
2020-12-28 15:19:12 -05:00
|
|
|
|
let content = b.as_str().get(old_len..).ok_or(RenderError::BufSize)?;
|
2020-12-19 06:38:55 -05:00
|
|
|
|
let s = content.to_lowercase();
|
2020-12-17 02:24:57 -05:00
|
|
|
|
unsafe { b._set_len(old_len) };
|
2020-07-14 18:31:07 -04:00
|
|
|
|
b.push_str(&*s);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
let old_len = b.len();
|
|
|
|
|
self.0.render_escaped(b)?;
|
|
|
|
|
|
|
|
|
|
let s = b.as_str()[old_len..].to_lowercase();
|
2020-12-17 02:24:57 -05:00
|
|
|
|
unsafe { b._set_len(old_len) };
|
2020-07-14 18:31:07 -04:00
|
|
|
|
b.push_str(&*s);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// convert the rendered contents to lowercase
|
2020-12-20 07:13:45 -05:00
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// <%= "ὈΔΥΣΣΕΎΣ" | lower %>
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// result:
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// ὀδυσσεύς
|
|
|
|
|
/// ```
|
2020-07-14 18:31:07 -04:00
|
|
|
|
#[inline]
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub fn lower<T: Render + ?Sized>(expr: &T) -> Lower<T> {
|
2020-07-14 18:31:07 -04:00
|
|
|
|
Lower(expr)
|
|
|
|
|
}
|
2020-07-15 06:34:53 -04:00
|
|
|
|
|
2020-12-20 07:20:52 -05:00
|
|
|
|
/// Helper struct for 'trim' filter
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub struct Trim<'a, T: ?Sized>(&'a T);
|
2020-07-21 17:22:31 -04:00
|
|
|
|
|
2020-12-28 08:33:49 -05:00
|
|
|
|
impl<'a, T: Render + ?Sized> Render for Trim<'a, T> {
|
2020-07-21 17:22:31 -04:00
|
|
|
|
#[inline]
|
|
|
|
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
let old_len = b.len();
|
|
|
|
|
self.0.render(b)?;
|
2020-12-19 06:38:55 -05:00
|
|
|
|
trim_impl(b, old_len)
|
2020-07-21 17:22:31 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
let old_len = b.len();
|
|
|
|
|
self.0.render_escaped(b)?;
|
2020-12-19 06:38:55 -05:00
|
|
|
|
trim_impl(b, old_len)
|
2020-07-21 17:22:31 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-19 06:38:55 -05:00
|
|
|
|
fn trim_impl(b: &mut Buffer, old_len: usize) -> Result<(), RenderError> {
|
2020-12-28 15:19:12 -05:00
|
|
|
|
let new_contents = b.as_str().get(old_len..).ok_or(RenderError::BufSize)?;
|
2020-12-19 06:38:55 -05:00
|
|
|
|
|
2020-07-21 17:22:31 -04:00
|
|
|
|
let trimmed = new_contents.trim();
|
|
|
|
|
let trimmed_len = trimmed.len();
|
|
|
|
|
|
|
|
|
|
if new_contents.len() != trimmed_len {
|
|
|
|
|
// performs inplace trimming
|
|
|
|
|
|
|
|
|
|
if new_contents.as_ptr() != trimmed.as_ptr() {
|
|
|
|
|
debug_assert!(new_contents.as_ptr() < trimmed.as_ptr());
|
|
|
|
|
let offset = trimmed.as_ptr() as usize - new_contents.as_ptr() as usize;
|
|
|
|
|
unsafe {
|
|
|
|
|
ptr::copy(
|
|
|
|
|
b.as_mut_ptr().add(old_len + offset),
|
|
|
|
|
b.as_mut_ptr().add(old_len),
|
|
|
|
|
trimmed_len,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug_assert!(b.capacity() >= old_len + trimmed_len);
|
2020-12-16 07:16:39 -05:00
|
|
|
|
|
|
|
|
|
// SAFETY: `new_contents.len() = b.len() - old_len` and
|
|
|
|
|
// `trimmed_len < new_contents.len()`, so `old_len + trimmed_len < b.len()`.
|
2020-07-21 17:22:31 -04:00
|
|
|
|
unsafe {
|
|
|
|
|
b._set_len(old_len + trimmed_len);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-19 06:38:55 -05:00
|
|
|
|
|
|
|
|
|
Ok(())
|
2020-07-21 17:22:31 -04:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-16 07:16:39 -05:00
|
|
|
|
/// Remove leading and trailing writespaces from rendered results
|
2020-12-20 07:13:45 -05:00
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// <%= " Hello world\n" | trim %>
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// result:
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// Hello world
|
|
|
|
|
/// ```
|
2020-07-21 17:22:31 -04:00
|
|
|
|
#[inline]
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub fn trim<T: Render + ?Sized>(expr: &T) -> Trim<T> {
|
2020-07-21 17:22:31 -04:00
|
|
|
|
Trim(expr)
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-20 07:20:52 -05:00
|
|
|
|
/// Helper struct for 'truncate' filter
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub struct Truncate<'a, T: ?Sized>(&'a T, usize);
|
2020-12-17 07:02:26 -05:00
|
|
|
|
|
2020-12-28 08:33:49 -05:00
|
|
|
|
impl<'a, T: Render + ?Sized> Render for Truncate<'a, T> {
|
2020-12-17 07:02:26 -05:00
|
|
|
|
#[inline]
|
|
|
|
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
let old_len = b.len();
|
|
|
|
|
self.0.render(b)?;
|
|
|
|
|
truncate_impl(b, old_len, self.1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
let old_len = b.len();
|
|
|
|
|
self.0.render_escaped(b)?;
|
|
|
|
|
truncate_impl(b, old_len, self.1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn truncate_impl(
|
|
|
|
|
b: &mut Buffer,
|
|
|
|
|
old_len: usize,
|
|
|
|
|
limit: usize,
|
|
|
|
|
) -> Result<(), RenderError> {
|
2020-12-28 15:19:12 -05:00
|
|
|
|
let new_contents = b.as_str().get(old_len..).ok_or(RenderError::BufSize)?;
|
2020-12-17 07:02:26 -05:00
|
|
|
|
|
2020-12-20 02:07:06 -05:00
|
|
|
|
if let Some(idx) = new_contents.char_indices().nth(limit).map(|(i, _)| i) {
|
|
|
|
|
unsafe { b._set_len(old_len.wrapping_add(idx)) };
|
2020-12-17 07:02:26 -05:00
|
|
|
|
b.push_str("...");
|
|
|
|
|
}
|
2020-12-20 02:07:06 -05:00
|
|
|
|
|
|
|
|
|
Ok(())
|
2020-12-17 07:02:26 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Limit length of rendered contents, appends '...' if truncated
|
2020-12-20 07:13:45 -05:00
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// The following example renders the first 20 characters of `message`
|
|
|
|
|
///
|
|
|
|
|
/// ```test
|
2020-12-28 07:28:53 -05:00
|
|
|
|
/// <%= "Hello, world!" | truncate(5) %>
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// result:
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// Hello...
|
2020-12-20 07:13:45 -05:00
|
|
|
|
/// ```
|
2020-12-17 07:02:26 -05:00
|
|
|
|
#[inline]
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub fn truncate<T: Render + ?Sized>(expr: &T, limit: usize) -> Truncate<T> {
|
2020-12-17 07:02:26 -05:00
|
|
|
|
Truncate(expr, limit)
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-17 04:00:05 -05:00
|
|
|
|
cfg_json! {
|
2020-12-20 07:20:52 -05:00
|
|
|
|
/// Helper struct for 'json' filter
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub struct Json<'a, T: ?Sized>(&'a T);
|
2020-12-17 04:00:05 -05:00
|
|
|
|
|
2020-12-28 08:33:49 -05:00
|
|
|
|
impl<'a, T: serde::Serialize + ?Sized> Render for Json<'a, T> {
|
2020-12-17 04:00:05 -05:00
|
|
|
|
#[inline]
|
|
|
|
|
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
struct Writer<'a>(&'a mut Buffer);
|
|
|
|
|
|
|
|
|
|
impl<'a> std::io::Write for Writer<'a> {
|
|
|
|
|
#[inline]
|
|
|
|
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
|
|
|
|
let buf = unsafe { std::str::from_utf8_unchecked(buf) };
|
|
|
|
|
self.0.push_str(buf);
|
|
|
|
|
Ok(buf.len())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
|
|
|
|
|
self.write(buf).map(|_| {})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn flush(&mut self) -> std::io::Result<()> {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
serde_json::to_writer(Writer(b), self.0)
|
|
|
|
|
.map_err(|e| RenderError::new(&e.to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
|
|
|
|
use super::escape::escape_to_buf;
|
|
|
|
|
|
|
|
|
|
struct Writer<'a>(&'a mut Buffer);
|
|
|
|
|
|
|
|
|
|
impl<'a> std::io::Write for Writer<'a> {
|
|
|
|
|
#[inline]
|
|
|
|
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
|
|
|
|
let buf = unsafe { std::str::from_utf8_unchecked(buf) };
|
|
|
|
|
escape_to_buf(buf, self.0);
|
|
|
|
|
Ok(buf.len())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
|
|
|
|
|
self.write(buf).map(|_| {})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn flush(&mut self) -> std::io::Result<()> {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
serde_json::to_writer(Writer(b), self.0)
|
|
|
|
|
.map_err(|e| RenderError::new(&e.to_string()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-17 04:01:17 -05:00
|
|
|
|
/// Serialize the given data structure as JSON into the buffer
|
2020-12-20 07:13:45 -05:00
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// {
|
|
|
|
|
/// "name": "JSON example",
|
|
|
|
|
/// "data": <%- data | json %>
|
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
2020-12-17 04:00:05 -05:00
|
|
|
|
#[inline]
|
2020-12-28 08:33:49 -05:00
|
|
|
|
pub fn json<T: serde::Serialize + ?Sized>(expr: &T) -> Json<T> {
|
2020-12-17 04:00:05 -05:00
|
|
|
|
Json(expr)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-15 06:34:53 -04:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
2020-12-28 08:44:36 -05:00
|
|
|
|
fn assert_render<T: Render>(expr: &T, expected: &str) {
|
2020-07-15 06:34:53 -04:00
|
|
|
|
let mut buf = Buffer::new();
|
2020-12-28 08:44:36 -05:00
|
|
|
|
Render::render(expr, &mut buf).unwrap();
|
|
|
|
|
assert_eq!(buf.as_str(), expected);
|
|
|
|
|
}
|
2020-07-15 06:34:53 -04:00
|
|
|
|
|
2020-12-28 08:44:36 -05:00
|
|
|
|
fn assert_render_escaped<T: Render>(expr: &T, expected: &str) {
|
|
|
|
|
let mut buf = Buffer::new();
|
|
|
|
|
Render::render_escaped(expr, &mut buf).unwrap();
|
|
|
|
|
assert_eq!(buf.as_str(), expected);
|
|
|
|
|
}
|
2020-07-15 06:34:53 -04:00
|
|
|
|
|
2020-12-28 08:44:36 -05:00
|
|
|
|
#[test]
|
2020-12-28 11:32:56 -05:00
|
|
|
|
fn test_lower() {
|
|
|
|
|
assert_render(&lower(""), "");
|
|
|
|
|
assert_render_escaped(&lower(""), "");
|
|
|
|
|
|
|
|
|
|
assert_render(&lower("lorem ipsum"), "lorem ipsum");
|
|
|
|
|
assert_render(&lower("LOREM IPSUM"), "lorem ipsum");
|
|
|
|
|
|
|
|
|
|
assert_render_escaped(&lower("hElLo, WOrLd!"), "hello, world!");
|
|
|
|
|
assert_render_escaped(&lower("hElLo, WOrLd!"), "hello, world!");
|
|
|
|
|
|
2020-12-28 08:44:36 -05:00
|
|
|
|
assert_render_escaped(&lower("<h1>TITLE</h1>"), "<h1>title</h1>");
|
2020-12-28 11:32:56 -05:00
|
|
|
|
assert_render_escaped(&lower("<<&\"\">>"), "<<&"">>");
|
|
|
|
|
|
|
|
|
|
// non-ascii
|
|
|
|
|
assert_render(&lower("aBcAbc"), "abcabc");
|
|
|
|
|
assert_render(&lower("ὈΔΥΣΣΕΎΣ"), "ὀδυσσεύς");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_upper() {
|
|
|
|
|
assert_render(&upper(""), "");
|
|
|
|
|
assert_render_escaped(&upper(""), "");
|
|
|
|
|
|
|
|
|
|
assert_render(&upper("lorem ipsum"), "LOREM IPSUM");
|
|
|
|
|
assert_render(&upper("LOREM IPSUM"), "LOREM IPSUM");
|
|
|
|
|
|
|
|
|
|
assert_render(&upper("hElLo, WOrLd!"), "HELLO, WORLD!");
|
|
|
|
|
assert_render(&upper("hElLo, WOrLd!"), "HELLO, WORLD!");
|
|
|
|
|
|
|
|
|
|
// non-ascii
|
|
|
|
|
assert_render(&upper("aBcAbc"), "ABCABC");
|
|
|
|
|
assert_render(&upper("tschüß"), "TSCHÜSS");
|
2020-07-15 06:34:53 -04:00
|
|
|
|
}
|
2020-07-21 17:22:31 -04:00
|
|
|
|
|
|
|
|
|
#[test]
|
2020-12-28 11:32:56 -05:00
|
|
|
|
fn test_trim() {
|
2020-12-28 08:44:36 -05:00
|
|
|
|
assert_render(&trim(""), "");
|
2020-12-28 11:32:56 -05:00
|
|
|
|
assert_render_escaped(&trim(""), "");
|
|
|
|
|
|
2020-12-28 08:44:36 -05:00
|
|
|
|
assert_render(&trim("\n \t\r\x0C"), "");
|
2020-07-21 17:22:31 -04:00
|
|
|
|
|
2020-12-28 08:44:36 -05:00
|
|
|
|
assert_render(&trim("hello world!"), "hello world!");
|
|
|
|
|
assert_render(&trim("hello world!\n"), "hello world!");
|
|
|
|
|
assert_render(&trim("\thello world!"), "hello world!");
|
|
|
|
|
assert_render(&trim("\thello world!\r\n"), "hello world!");
|
2020-12-28 11:32:56 -05:00
|
|
|
|
|
|
|
|
|
assert_render_escaped(&trim(" <html> "), "<html>");
|
|
|
|
|
assert_render_escaped(&lower("<<&\"\">>"), "<<&"">>");
|
|
|
|
|
|
|
|
|
|
// non-ascii whitespace
|
|
|
|
|
assert_render(&trim("\u{A0}空白\u{3000}\u{205F}"), "空白");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_truncate() {
|
|
|
|
|
assert_render(&truncate("", 0), "");
|
|
|
|
|
assert_render(&truncate("", 5), "");
|
|
|
|
|
|
|
|
|
|
assert_render(&truncate("apple ", 0), "...");
|
|
|
|
|
assert_render(&truncate("apple ", 1), "a...");
|
|
|
|
|
assert_render(&truncate("apple ", 2), "ap...");
|
|
|
|
|
assert_render(&truncate("apple ", 3), "app...");
|
|
|
|
|
assert_render(&truncate("apple ", 4), "appl...");
|
|
|
|
|
assert_render(&truncate("apple ", 5), "apple...");
|
|
|
|
|
assert_render(&truncate("apple ", 6), "apple ");
|
|
|
|
|
assert_render(&truncate("apple ", 7), "apple ");
|
|
|
|
|
|
|
|
|
|
assert_render(&truncate(&std::f64::consts::PI, 10), "3.14159265...");
|
|
|
|
|
assert_render(&truncate(&std::f64::consts::PI, 20), "3.141592653589793");
|
|
|
|
|
|
|
|
|
|
assert_render_escaped(&truncate("foo<br>bar", 10), "foo<br&...");
|
|
|
|
|
assert_render_escaped(&truncate("foo<br>bar", 20), "foo<br>bar");
|
|
|
|
|
|
|
|
|
|
// non-ascii
|
|
|
|
|
assert_render(&truncate("魑魅魍魎", 0), "...");
|
|
|
|
|
assert_render(&truncate("魑魅魍魎", 1), "魑...");
|
|
|
|
|
assert_render(&truncate("魑魅魍魎", 2), "魑魅...");
|
|
|
|
|
assert_render(&truncate("魑魅魍魎", 3), "魑魅魍...");
|
|
|
|
|
assert_render(&truncate("魑魅魍魎", 4), "魑魅魍魎");
|
|
|
|
|
assert_render(&truncate("魑魅魍魎", 5), "魑魅魍魎");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "json")]
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_json() {
|
|
|
|
|
assert_render(&json(""), "\"\"");
|
|
|
|
|
assert_render(&json(&serde_json::json!({})), "{}");
|
|
|
|
|
|
|
|
|
|
assert_render_escaped(&json(&123_i32), "123");
|
|
|
|
|
assert_render_escaped(&json("Pokémon"), ""Pokémon"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn compine() {
|
|
|
|
|
assert_render(
|
|
|
|
|
&lower(&upper("Li Europan lingues es membres del sam familie.")),
|
|
|
|
|
"li europan lingues es membres del sam familie.",
|
|
|
|
|
);
|
|
|
|
|
assert_render(&lower(&lower("ハートのA")), "ハートのa");
|
|
|
|
|
assert_render(&upper(&upper("ハートのA")), "ハートのA");
|
|
|
|
|
|
|
|
|
|
assert_render(&truncate(&trim("\t起来!\r\n"), 1), "起...");
|
|
|
|
|
assert_render(&truncate(&trim("\t起来!\r\n"), 3), "起来!");
|
|
|
|
|
|
|
|
|
|
assert_render(&truncate(&lower("Was möchtest du?"), 10), "was möchte...");
|
|
|
|
|
assert_render(&truncate(&upper("Was möchtest du?"), 10), "WAS MÖCHTE...");
|
2020-07-21 17:22:31 -04:00
|
|
|
|
}
|
2020-07-15 06:34:53 -04:00
|
|
|
|
}
|