use crate::cli_pretty_printing::decoded_how_many_times;
use crate::filtration_system::MyResults;
use crossbeam::channel::Sender;
use log::trace;
use std::collections::HashSet;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use crate::DecoderResult;
#[allow(dead_code)]
pub fn bfs(input: String, result_sender: Sender<Option<DecoderResult>>, stop: Arc<AtomicBool>) {
let initial = DecoderResult {
text: vec![input],
path: vec![],
};
let mut seen_strings = HashSet::new();
let mut current_strings = vec![initial];
let mut curr_depth: u32 = 1;
while !current_strings.is_empty() && !stop.load(std::sync::atomic::Ordering::Relaxed) {
trace!("Number of potential decodings: {}", current_strings.len());
trace!("Current depth is {:?}", curr_depth);
let mut new_strings: Vec<DecoderResult> = vec![];
current_strings.into_iter().try_for_each(|current_string| {
let res = super::perform_decoding(¤t_string);
match res {
MyResults::Break(res) => {
let mut decoders_used = current_string.path;
let text = res.unencrypted_text.clone().unwrap_or_default();
decoders_used.push(res);
let result_text = DecoderResult {
text,
path: decoders_used,
};
decoded_how_many_times(curr_depth);
result_sender
.send(Some(result_text))
.expect("Should succesfully send the result");
stop.store(true, std::sync::atomic::Ordering::Relaxed);
None }
MyResults::Continue(results_vec) => {
new_strings.extend(results_vec.into_iter().flat_map(|mut r| {
let mut decoders_used = current_string.path.clone();
let mut text = r.unencrypted_text.take().unwrap_or_default();
text.retain(|s| {
!check_if_string_cant_be_decoded(s) && seen_strings.insert(s.clone())
});
if text.is_empty() {
return None;
}
decoders_used.push(r);
Some(DecoderResult {
text,
path: decoders_used.to_vec(),
})
}));
Some(()) }
}
});
current_strings = new_strings;
curr_depth += 1;
trace!("Refreshed the vector, {:?}", current_strings);
}
result_sender.try_send(None).ok();
}
#[allow(dead_code)]
fn check_if_string_cant_be_decoded(text: &str) -> bool {
text.len() <= 2
}
#[cfg(test)]
mod tests {
use crossbeam::channel::bounded;
use super::*;
#[test]
fn bfs_succeeds() {
let (tx, rx) = bounded::<Option<DecoderResult>>(1);
let stopper = Arc::new(AtomicBool::new(false));
bfs("b2xsZWg=".into(), tx, stopper);
let result = rx.recv().unwrap();
assert!(result.is_some());
}
#[test]
fn non_deterministic_like_behaviour_regression_test() {
let (tx, rx) = bounded::<Option<DecoderResult>>(1);
let stopper = Arc::new(AtomicBool::new(false));
bfs("MTkyLjE2OC4wLjE=".into(), tx, stopper);
let result = rx.recv().unwrap();
assert!(result.is_some());
assert_eq!(result.unwrap().text[0], "192.168.0.1");
}
#[test]
fn string_size_checker_returns_bad_if_string_cant_be_decoded() {
let text = "12";
assert!(check_if_string_cant_be_decoded(text));
}
#[test]
fn string_size_checker_returns_ok_if_string_can_be_decoded() {
let text = "123";
assert!(!check_if_string_cant_be_decoded(text));
}
}