#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct FirefoxOptions {
pub headless: bool,
pub window_size: Option<(u32, u32)>,
pub kiosk: bool,
pub devtools: bool,
pub private: bool,
pub extra_args: Vec<String>,
}
impl FirefoxOptions {
#[inline]
#[must_use]
pub const fn new() -> Self {
Self {
headless: false,
window_size: None,
kiosk: false,
devtools: false,
private: false,
extra_args: Vec::new(),
}
}
#[inline]
#[must_use]
pub fn headless() -> Self {
Self {
headless: true,
..Default::default()
}
}
}
impl FirefoxOptions {
#[inline]
#[must_use]
pub fn with_headless(mut self) -> Self {
self.headless = true;
self
}
#[inline]
#[must_use]
pub fn with_window_size(mut self, width: u32, height: u32) -> Self {
self.window_size = Some((width, height));
self
}
#[inline]
#[must_use]
pub fn with_kiosk(mut self) -> Self {
self.kiosk = true;
self
}
#[inline]
#[must_use]
pub fn with_devtools(mut self) -> Self {
self.devtools = true;
self
}
#[inline]
#[must_use]
pub fn with_private(mut self) -> Self {
self.private = true;
self
}
#[inline]
#[must_use]
pub fn with_arg(mut self, arg: impl Into<String>) -> Self {
self.extra_args.push(arg.into());
self
}
#[inline]
#[must_use]
pub fn with_args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.extra_args.extend(args.into_iter().map(Into::into));
self
}
}
impl FirefoxOptions {
#[must_use]
pub fn to_args(&self) -> Vec<String> {
let mut args = Vec::with_capacity(8 + self.extra_args.len());
if self.headless {
args.push("--headless".to_string());
}
if let Some((width, height)) = self.window_size {
args.push("--window-size".to_string());
args.push(format!("{width},{height}"));
}
if self.kiosk {
args.push("--kiosk".to_string());
}
if self.devtools {
args.push("--devtools".to_string());
}
if self.private {
args.push("--private-window".to_string());
}
args.extend(self.extra_args.clone());
args
}
pub fn validate(&self) -> Result<(), String> {
if let Some((width, height)) = self.window_size
&& (width == 0 || height == 0)
{
return Err("Window dimensions must be greater than zero".to_string());
}
Ok(())
}
#[inline]
#[must_use]
pub const fn is_headless(&self) -> bool {
self.headless
}
#[inline]
#[must_use]
pub const fn is_private(&self) -> bool {
self.private
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_creates_default() {
let options = FirefoxOptions::new();
assert!(!options.headless);
assert!(options.window_size.is_none());
assert!(!options.kiosk);
assert!(!options.devtools);
assert!(!options.private);
assert!(options.extra_args.is_empty());
}
#[test]
fn test_headless_constructor() {
let options = FirefoxOptions::headless();
assert!(options.headless);
assert!(options.is_headless());
}
#[test]
fn test_builder_chain() {
let options = FirefoxOptions::new()
.with_headless()
.with_window_size(1920, 1080)
.with_devtools()
.with_private();
assert!(options.headless);
assert_eq!(options.window_size, Some((1920, 1080)));
assert!(options.devtools);
assert!(options.private);
}
#[test]
fn test_to_args_headless() {
let options = FirefoxOptions::new().with_headless();
let args = options.to_args();
assert!(args.contains(&"--headless".to_string()));
}
#[test]
fn test_to_args_window_size() {
let options = FirefoxOptions::new().with_window_size(800, 600);
let args = options.to_args();
assert!(args.contains(&"--window-size".to_string()));
assert!(args.contains(&"800,600".to_string()));
}
#[test]
fn test_to_args_all_options() {
let options = FirefoxOptions::new()
.with_headless()
.with_window_size(1024, 768)
.with_kiosk()
.with_devtools()
.with_private()
.with_arg("--custom");
let args = options.to_args();
assert!(args.contains(&"--headless".to_string()));
assert!(args.contains(&"--kiosk".to_string()));
assert!(args.contains(&"--devtools".to_string()));
assert!(args.contains(&"--private-window".to_string()));
assert!(args.contains(&"--custom".to_string()));
}
#[test]
fn test_with_args_multiple() {
let options = FirefoxOptions::new().with_args(["--arg1", "--arg2"]);
assert_eq!(options.extra_args.len(), 2);
}
#[test]
fn test_validate_valid() {
let options = FirefoxOptions::new().with_window_size(800, 600);
assert!(options.validate().is_ok());
}
#[test]
fn test_validate_zero_width() {
let options = FirefoxOptions::new().with_window_size(0, 600);
assert!(options.validate().is_err());
}
#[test]
fn test_validate_zero_height() {
let options = FirefoxOptions::new().with_window_size(800, 0);
assert!(options.validate().is_err());
}
}