use ezcapsolver::{
AkamaiSbsdTask, AkamaiWebTask, Cloudflare5sTask, CloudflareTurnstileTask, DataDomeJsType,
DataDomeStep, DataDomeTagsTask, DataDomeTask, ExtraFields, FunCaptchaClassificationTask,
FunCaptchaTask, HcaptchaClassificationTask, HcaptchaTask, IncapsulaTask, PerimeterXTask,
RecaptchaV2ClassificationTask, RecaptchaV2Task, RecaptchaV2TaskBuilder, RecaptchaV3Task,
TlsForwardTask, TlsHttpMethod,
};
use serde_json::json;
#[test]
fn every_task_builder_preserves_existing_defaults() -> Result<(), serde_json::Error> {
macro_rules! assert_matches_literal {
($task:ident { $($field:ident: $value:expr),* $(,)? }) => {
let built = $task::builder()$(.$field($value))*.build();
let literal = $task {
$($field: $value.into(),)*
..Default::default()
};
assert_eq!(
serde_json::to_value(built)?,
serde_json::to_value(literal)?,
"{} builder defaults changed the wire payload",
stringify!($task),
);
};
}
assert_matches_literal!(RecaptchaV2Task {
website_url: "https://example.com",
website_key: "site-key",
});
assert_matches_literal!(RecaptchaV3Task {
website_url: "https://example.com",
website_key: "site-key",
});
assert_matches_literal!(RecaptchaV2ClassificationTask {
image: "image-data",
question: "question",
});
assert_matches_literal!(FunCaptchaTask {
website_url: "https://example.com",
website_key: "site-key",
});
assert_matches_literal!(FunCaptchaClassificationTask {
image: "image-data",
question: "question",
});
assert_matches_literal!(HcaptchaTask {
website_url: "https://example.com",
website_key: "site-key",
lang: "en-US",
invisible: false,
});
assert_matches_literal!(HcaptchaClassificationTask {});
assert_matches_literal!(Cloudflare5sTask {
website_url: "https://example.com",
proxy: "http://127.0.0.1:8080",
});
assert_matches_literal!(CloudflareTurnstileTask {
website_url: "https://example.com",
website_key: "site-key",
});
assert_matches_literal!(AkamaiWebTask {
page_url: "https://example.com",
v3_url: "https://example.com/v3.js",
ua: "user-agent",
lang: "en",
index: 0_i32,
});
assert_matches_literal!(AkamaiSbsdTask {
page_url: "https://example.com",
sbsd_url: "https://example.com/script.js",
bm_so: "state",
ua: "user-agent",
lang: "en",
script_base64: "script-data",
});
assert_matches_literal!(DataDomeTask {
html_b64: "html-data",
});
assert_matches_literal!(DataDomeTagsTask {
ddk: "key",
bpc: 1_u64,
referer: "https://example.com",
ua: "user-agent",
});
assert_matches_literal!(IncapsulaTask {});
assert_matches_literal!(PerimeterXTask {
website_key: "site-key",
});
assert_matches_literal!(TlsForwardTask {
tls_type: "fingerprint",
proxy: "http://127.0.0.1:8080",
url: "https://example.com",
});
Ok(())
}
#[test]
fn string_setters_accept_borrowed_owned_and_optional_values() -> Result<(), serde_json::Error> {
let website_url = "https://example.com".to_owned();
let website_key = "site-key".to_owned();
let proxy = Some("http://127.0.0.1:8080");
let title: Option<String> = None;
let builder: RecaptchaV2TaskBuilder = RecaptchaV2Task::builder();
let task = builder
.website_url(&website_url)
.website_key(website_key)
.s("challenge-data")
.maybe_sa(Some("anchor".to_owned()))
.maybe_proxy(proxy)
.maybe_website_title(title)
.build();
assert_eq!(task.website_url, website_url);
assert_eq!(task.website_key, "site-key");
assert_eq!(task.s.as_deref(), Some("challenge-data"));
assert_eq!(task.sa.as_deref(), Some("anchor"));
assert_eq!(task.proxy.as_deref(), proxy);
assert!(task.website_title.is_none());
assert_eq!(
serde_json::to_value(task)?,
json!({
"websiteURL": "https://example.com",
"websiteKey": "site-key",
"isInvisible": false,
"s": "challenge-data",
"sa": "anchor",
"proxy": "http://127.0.0.1:8080"
})
);
Ok(())
}
#[test]
fn builder_defaults_can_be_overridden() {
let v3 = RecaptchaV3Task::builder()
.website_url("https://example.com")
.website_key("site-key")
.is_invisible(false)
.page_action("action")
.build();
assert!(!v3.is_invisible);
assert_eq!(v3.page_action.as_deref(), Some("action"));
let classification = RecaptchaV2ClassificationTask::builder()
.image("image-data")
.question("question")
.size(1)
.build();
assert_eq!(classification.size, 1);
let data_dome = DataDomeTask::builder()
.html_b64("html-data")
.step(DataDomeStep::Two)
.image("image-data")
.build();
assert_eq!(data_dome.step, DataDomeStep::Two);
assert_eq!(data_dome.image, "image-data");
let tags = DataDomeTagsTask::builder()
.ddk("key")
.bpc(2)
.referer("https://example.com")
.ua("user-agent")
.jstype(DataDomeJsType::Le)
.cid("session")
.build();
assert_eq!(tags.jstype, DataDomeJsType::Le);
assert_eq!(tags.cid, "session");
}
#[test]
fn optional_collections_and_json_values_keep_their_wire_shape() -> Result<(), serde_json::Error> {
let task = TlsForwardTask::builder()
.tls_type("fingerprint")
.proxy("http://127.0.0.1:8080")
.url("https://example.com")
.method(TlsHttpMethod::Post)
.headers(ExtraFields::from([(
"accept".into(),
json!("application/json"),
)]))
.maybe_cookies(None)
.headers_order("accept")
.body(json!({"data": [1, 2]}))
.extra(ExtraFields::from([("futureFlag".into(), json!(true))]))
.build();
assert_eq!(
serde_json::to_value(task)?,
json!({
"tls_type": "fingerprint",
"proxy": "http://127.0.0.1:8080",
"url": "https://example.com",
"method": "POST",
"headers": {"accept": "application/json"},
"headers_order": "accept",
"body": {"data": [1, 2]},
"body_raw": false,
"futureFlag": true
})
);
let classification = HcaptchaClassificationTask::builder()
.images(vec!["first".to_owned(), "second".to_owned()])
.maybe_anchors(Some(vec!["anchor".to_owned()]))
.question("question")
.build();
assert_eq!(
serde_json::to_value(classification)?,
json!({"images": ["first", "second"], "anchors": ["anchor"], "question": "question"})
);
Ok(())
}
#[test]
fn runtime_none_uses_the_models_special_default() {
let task = RecaptchaV3Task::builder()
.website_url("https://example.com")
.website_key("site-key")
.maybe_is_invisible(None)
.build();
assert!(task.is_invisible);
let classification = RecaptchaV2ClassificationTask::builder()
.image("image-data")
.question("question")
.maybe_size(None)
.build();
assert_eq!(classification.size, 4);
}
#[test]
fn model_defaults_stay_inside_the_service_value_ranges() {
assert!(
DataDomeTagsTask::default().bpc >= 1,
"bpc must default inside the range the service accepts",
);
assert!(RecaptchaV3Task::default().is_invisible);
assert_eq!(RecaptchaV2ClassificationTask::default().size, 4);
assert_eq!(DataDomeTask::default().step, DataDomeStep::One);
assert_eq!(DataDomeTagsTask::default().jstype, DataDomeJsType::Ch);
assert_eq!(TlsForwardTask::default().method, TlsHttpMethod::Get);
}