#![cfg_attr(coverage_nightly, coverage(off))]
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use tracing::{debug, info};
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub struct StatementId {
pub file: PathBuf,
pub line: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub column: Option<usize>,
}
impl StatementId {
pub fn new(file: impl Into<PathBuf>, line: usize) -> Self {
Self {
file: file.into(),
line,
column: None,
}
}
#[allow(dead_code)]
pub fn with_column(mut self, column: usize) -> Self {
self.column = Some(column);
self
}
}
impl std::fmt::Display for StatementId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.file.display(), self.line)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StatementCoverage {
pub id: StatementId,
pub executed_by_passed: usize,
pub executed_by_failed: usize,
}
impl StatementCoverage {
pub fn new(id: StatementId, passed: usize, failed: usize) -> Self {
Self {
id,
executed_by_passed: passed,
executed_by_failed: failed,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum SbflFormula {
#[default]
Tarantula,
Ochiai,
DStar { exponent: u32 },
}
impl std::fmt::Display for SbflFormula {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SbflFormula::Tarantula => write!(f, "Tarantula"),
SbflFormula::Ochiai => write!(f, "Ochiai"),
SbflFormula::DStar { exponent } => write!(f, "DStar{}", exponent),
}
}
}
impl std::str::FromStr for SbflFormula {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"tarantula" => Ok(SbflFormula::Tarantula),
"ochiai" => Ok(SbflFormula::Ochiai),
"dstar2" => Ok(SbflFormula::DStar { exponent: 2 }),
"dstar3" => Ok(SbflFormula::DStar { exponent: 3 }),
other => Err(anyhow!("Unknown SBFL formula: {}", other)),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SuspiciousnessRanking {
pub rank: usize,
pub statement: StatementId,
pub suspiciousness: f32,
pub scores: HashMap<String, f32>,
pub explanation: String,
pub failed_coverage: usize,
pub passed_coverage: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FaultLocalizationResult {
pub rankings: Vec<SuspiciousnessRanking>,
pub formula_used: SbflFormula,
pub confidence: f32,
pub total_passed_tests: usize,
pub total_failed_tests: usize,
}
pub struct SbflLocalizer {
formula: SbflFormula,
top_n: usize,
include_explanations: bool,
min_confidence_threshold: f32,
}
impl Default for SbflLocalizer {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ReportFormat {
#[default]
Terminal,
Json,
Yaml,
}
impl std::str::FromStr for ReportFormat {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"terminal" | "text" => Ok(ReportFormat::Terminal),
"json" => Ok(ReportFormat::Json),
"yaml" => Ok(ReportFormat::Yaml),
other => Err(anyhow!("Unknown format: {}", other)),
}
}
}
#[derive(Debug, Default)]
pub struct LcovParser;
pub struct FaultLocalizer;
include!("fault_localization_formulas.rs");
include!("fault_localization_parsing.rs");
include!("fault_localization_tests.rs");