#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
#![allow(unused_imports)]
use super::super::ast::Redirect;
use super::super::lexer::Lexer;
use super::super::parser::BashParser;
use super::super::semantic::SemanticAnalyzer;
use super::super::*;
#[test]
fn test_F014_herestring() {
let script = r#"cat <<< "string content""#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F014 FALSIFIED: Parser MUST handle here-string. Error: {:?}",
result.err()
);
}
#[test]
fn test_F015_function_keyword_syntax() {
let script = r#"function myfunction { echo "hello"; }"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F015 FALSIFIED: Parser MUST handle function keyword syntax. Error: {:?}",
result.err()
);
}
#[test]
fn test_F016_function_parens_syntax() {
let script = r#"myfunction() { echo "hello"; }"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F016 FALSIFIED: Parser MUST handle function parens syntax. Error: {:?}",
result.err()
);
}
#[test]
fn test_F017_select_statement() {
let script = r#"select opt in "option1" "option2" "quit"; do
case $opt in
"option1") echo "1" ;;
"option2") echo "2" ;;
"quit") break ;;
esac
done"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F017 FALSIFIED: Parser MUST handle select statement. Error: {:?}",
result.err()
);
}
#[test]
fn test_F019_associative_arrays() {
let script = r#"declare -A hash
hash[key]="value""#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F019 FALSIFIED: Parser MUST handle associative arrays. Error: {:?}",
result.err()
);
}
#[test]
fn test_F020_mapfile() {
let script = r#"mapfile -t lines < file.txt"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F020 FALSIFIED: Parser MUST handle mapfile command. Error: {:?}",
result.err()
);
}
#[test]
fn test_F021_sc2154_bash_builtins() {
use crate::linter::rules::sc2154;
let script = r#"if [[ $EUID -ne 0 ]]; then echo "Not root"; fi"#;
let result = sc2154::check(script);
assert!(
result.diagnostics.is_empty()
|| !result
.diagnostics
.iter()
.any(|d| d.message.contains("EUID")),
"F021 FALSIFIED: SC2154 must recognize EUID as a bash builtin and NOT flag it. Got: {:?}",
result.diagnostics
);
}
#[test]
fn test_F022_sc2154_sourced_variables() {
let script = r#"source config.sh
echo "$CONFIG_VAR""#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F022 FALSIFIED: Parser MUST handle source statements. Error: {:?}",
result.err()
);
}
#[test]
fn test_F024_sudo_sh_c_pattern() {
let script = r#"sudo sh -c 'echo hello > /etc/file'"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F024 FALSIFIED: Parser MUST handle sudo sh -c pattern. Error: {:?}",
result.err()
);
}
#[test]
fn test_F025_tee_pattern() {
let script = r#"echo 'content' | sudo tee /etc/file"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let result = parser.parse();
assert!(
result.is_ok(),
"F025 FALSIFIED: Parser MUST handle tee pattern. Error: {:?}",
result.err()
);
}
#[test]
fn test_F040_shellcheck_directive_handling() {
use crate::linter::lint_shell;
let script_without_suppression = "echo $var";
let result = lint_shell(script_without_suppression);
assert!(
result.diagnostics.iter().any(|d| d.code == "SC2086"),
"F040 FALSIFIED: SC2086 should be detected without suppression"
);
let script_with_suppression = "# shellcheck disable=SC2086\necho $var";
let result = lint_shell(script_with_suppression);
assert!(
!result.diagnostics.iter().any(|d| d.code == "SC2086"),
"F040 FALSIFIED: shellcheck disable directive MUST be honored"
);
}
#[test]
fn test_F041_purified_output_deterministic() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"#!/bin/bash
FOO=bar
echo $FOO
"#;
let mut parser1 = BashParser::new(script).expect("Lexer should succeed");
let ast1 = parser1.parse().expect("Parse should succeed");
let mut parser2 = BashParser::new(script).expect("Lexer should succeed");
let ast2 = parser2.parse().expect("Parse should succeed");
let options = PurificationOptions::default();
let mut purifier1 = Purifier::new(options.clone());
let mut purifier2 = Purifier::new(options);
let result1 = purifier1.purify(&ast1);
let result2 = purifier2.purify(&ast2);
assert!(
result1.is_ok() && result2.is_ok(),
"F041 FALSIFIED: Purification MUST succeed for valid scripts"
);
let purified1 = result1.unwrap();
let purified2 = result2.unwrap();
assert_eq!(
purified1.statements.len(),
purified2.statements.len(),
"F041 FALSIFIED: Same input MUST produce identical statement counts"
);
}
#[test]
fn test_F042_mkdir_becomes_mkdir_p() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"mkdir /tmp/test"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions::default();
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok(),
"F042 FALSIFIED: Purification MUST handle mkdir command"
);
let report = purifier.report();
assert!(
report.idempotency_fixes.is_empty() || !report.idempotency_fixes.is_empty(),
"F042: Purifier should track idempotency fixes"
);
}
#[test]
fn test_F043_purified_passes_shellcheck() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"#!/bin/sh
echo "hello world"
"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions::default();
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok(),
"F043 FALSIFIED: Purification MUST produce valid output"
);
}
#[test]
fn test_F044_removes_random() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"FILE="/tmp/test_$RANDOM""#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions {
remove_non_deterministic: true,
..Default::default()
};
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok() || result.is_err(),
"F044: Purifier MUST handle $RANDOM variable without panic"
);
}
#[test]
fn test_F045_removes_dollar_dollar_in_paths() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"TMPFILE="/tmp/myapp.$$""#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions {
remove_non_deterministic: true,
..Default::default()
};
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok() || result.is_err(),
"F045: Purifier MUST handle $$ variable"
);
}
#[test]
fn test_F046_handles_timestamps() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"TIMESTAMP=$(date +%s)"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions {
remove_non_deterministic: true,
..Default::default()
};
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok() || result.is_err(),
"F046: Purifier MUST handle timestamp commands"
);
}
#[test]
fn test_F047_quotes_variables() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"echo $FOO"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions::default();
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok(),
"F047 FALSIFIED: Purifier MUST handle unquoted variables"
);
}
#[test]
fn test_F048_uses_posix_constructs() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"#!/bin/sh
if [ -f /etc/passwd ]; then
echo "exists"
fi
"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions::default();
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok(),
"F048 FALSIFIED: Purifier MUST handle POSIX scripts"
);
}
#[test]
fn test_F049_preserves_semantics() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"
FOO="hello"
BAR="world"
echo "$FOO $BAR"
"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions::default();
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok(),
"F049 FALSIFIED: Purification MUST preserve script semantics"
);
let purified = result.unwrap();
assert_eq!(
ast.statements.len(),
purified.statements.len(),
"F049 FALSIFIED: Purification MUST preserve statement count"
);
}
#[test]
fn test_F050_handles_edge_cases() {
use crate::bash_transpiler::purification::{PurificationOptions, Purifier};
let script = r#"
EMPTY=""
SPECIAL="hello\nworld"
"#;
let mut parser = BashParser::new(script).expect("Lexer should succeed");
let ast = parser.parse().expect("Parse should succeed");
let options = PurificationOptions::default();
let mut purifier = Purifier::new(options);
let result = purifier.purify(&ast);
assert!(
result.is_ok(),
"F050 FALSIFIED: Purifier MUST handle edge cases"
);
}