|
|
"""
|
|
|
Mutate模块单元测试
|
|
|
|
|
|
本模块为mutate模块提供全面的单元测试覆盖,包括:
|
|
|
- CBMCMutationOperators测试
|
|
|
- SpecSelector测试
|
|
|
- QualityEvaluator测试
|
|
|
- MutationEngine测试
|
|
|
- 突变策略测试
|
|
|
- 质量评估测试
|
|
|
"""
|
|
|
|
|
|
import pytest
|
|
|
import asyncio
|
|
|
import tempfile
|
|
|
import json
|
|
|
from pathlib import Path
|
|
|
from unittest.mock import Mock, patch, MagicMock
|
|
|
from typing import Dict, List, Any, Optional, Tuple
|
|
|
import statistics
|
|
|
|
|
|
from src.mutate.operators import CBMCMutationOperators, MutationPattern
|
|
|
from src.mutate.selector import SpecSelector, SelectionWeights, SelectionStrategy
|
|
|
from src.mutate.evaluator import QualityEvaluator, EvaluationWeights
|
|
|
from src.mutate.engine import MutationEngine, MutationStrategy, MutationConfig
|
|
|
from src.mutate.mutation_types import (
|
|
|
MutationType, MutationCandidate, MutationOperation, MutationResult,
|
|
|
MutationSession, SelectionHistory, QualityMetrics, QualityDimension,
|
|
|
VerificationResult, VerificationStatus
|
|
|
)
|
|
|
from src.mutate.exceptions import (
|
|
|
OperatorError, ValidationError, SelectionError, EvaluationError,
|
|
|
MutationError, ResourceError
|
|
|
)
|
|
|
from src.utils.config import ConfigManager
|
|
|
|
|
|
|
|
|
class TestCBMCMutationOperators:
|
|
|
"""CBMCMutationOperators类测试"""
|
|
|
|
|
|
def setup_method(self):
|
|
|
"""测试方法设置"""
|
|
|
self.operators = CBMCMutationOperators()
|
|
|
|
|
|
def test_init(self):
|
|
|
"""测试初始化"""
|
|
|
assert self.operators.patterns is not None
|
|
|
assert len(self.operators.patterns) > 0
|
|
|
assert MutationType.PREDICATE in self.operators.patterns
|
|
|
|
|
|
def test_predicate_mutation_basic(self):
|
|
|
"""测试基本谓词突变"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
candidates = self.operators.generate_mutations(spec, [MutationType.PREDICATE])
|
|
|
|
|
|
assert len(candidates) > 0
|
|
|
for candidate in candidates:
|
|
|
assert candidate.mutation_type == MutationType.PREDICATE
|
|
|
assert candidate.original_spec == spec
|
|
|
assert candidate.mutated_spec != spec
|
|
|
assert candidate.confidence > 0
|
|
|
|
|
|
def test_boundary_mutation_basic(self):
|
|
|
"""测试基本边界突变"""
|
|
|
spec = "void test(int x) { if (x < 10) { /* code */ } }"
|
|
|
candidates = self.operators.generate_mutations(spec, [MutationType.BOUNDARY])
|
|
|
|
|
|
assert len(candidates) > 0
|
|
|
for candidate in candidates:
|
|
|
assert candidate.mutation_type == MutationType.BOUNDARY
|
|
|
assert "boundary" in candidate.description.lower()
|
|
|
|
|
|
def test_logical_mutation_basic(self):
|
|
|
"""测试基本逻辑突变"""
|
|
|
spec = "void test(int x, int y) { if (x > 0 && y < 10) { /* code */ } }"
|
|
|
candidates = self.operators.generate_mutations(spec, [MutationType.LOGICAL])
|
|
|
|
|
|
assert len(candidates) > 0
|
|
|
for candidate in candidates:
|
|
|
assert candidate.mutation_type == MutationType.LOGICAL
|
|
|
assert "logical" in candidate.description.lower()
|
|
|
|
|
|
def test_array_bounds_mutation_basic(self):
|
|
|
"""测试数组边界突变"""
|
|
|
spec = "void test(int arr[10]) { __CPROVER_assume(arr[5] == 0); }"
|
|
|
candidates = self.operators.generate_mutations(spec, [MutationType.ARRAY_BOUNDS])
|
|
|
|
|
|
assert len(candidates) > 0
|
|
|
for candidate in candidates:
|
|
|
assert candidate.mutation_type == MutationType.ARRAY_BOUNDS
|
|
|
assert "array" in candidate.description.lower()
|
|
|
|
|
|
def test_pointer_validity_mutation_basic(self):
|
|
|
"""测试指针有效性突变"""
|
|
|
spec = "void test(int *ptr) { __CPROVER_assert(ptr != NULL, \"valid pointer\"); }"
|
|
|
candidates = self.operators.generate_mutations(spec, [MutationType.POINTER_VALIDITY])
|
|
|
|
|
|
assert len(candidates) > 0
|
|
|
for candidate in candidates:
|
|
|
assert candidate.mutation_type == MutationType.POINTER_VALIDITY
|
|
|
assert "pointer" in candidate.description.lower()
|
|
|
|
|
|
def test_combined_mutation_types(self):
|
|
|
"""测试组合突变类型"""
|
|
|
spec = "void test(int x, int *ptr) { if (x > 0 && ptr != NULL) { /* code */ } }"
|
|
|
mutation_types = [
|
|
|
MutationType.PREDICATE,
|
|
|
MutationType.LOGICAL,
|
|
|
MutationType.POINTER_VALIDITY
|
|
|
]
|
|
|
|
|
|
candidates = self.operators.generate_mutations(spec, mutation_types)
|
|
|
|
|
|
assert len(candidates) > 0
|
|
|
found_types = {candidate.mutation_type for candidate in candidates}
|
|
|
assert found_types.issuperset(mutation_types)
|
|
|
|
|
|
def test_mutation_validation(self):
|
|
|
"""测试突变验证"""
|
|
|
valid_spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
candidates = self.operators.generate_mutations(valid_spec, [MutationType.PREDICATE])
|
|
|
|
|
|
for candidate in candidates:
|
|
|
is_valid = self.operators.validate_mutation(candidate)
|
|
|
assert is_valid is True
|
|
|
|
|
|
def test_mutation_conflict_detection(self):
|
|
|
"""测试突变冲突检测"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
candidates = self.operators.generate_mutations(spec, [MutationType.PREDICATE])
|
|
|
|
|
|
if len(candidates) > 1:
|
|
|
conflicts = self.operators.detect_conflicts(candidates)
|
|
|
# 某些突变可能会有冲突
|
|
|
assert isinstance(conflicts, list)
|
|
|
|
|
|
def test_batch_mutation_generation(self):
|
|
|
"""测试批量突变生成"""
|
|
|
specs = [
|
|
|
"void test1(int x) { __CPROVER_assume(x > 0); }",
|
|
|
"void test2(int y) { if (y < 10) { /* code */ } }"
|
|
|
]
|
|
|
|
|
|
batch_results = self.operators.generate_batch_mutations(specs, [MutationType.PREDICATE])
|
|
|
|
|
|
assert len(batch_results) == len(specs)
|
|
|
for spec, candidates in batch_results.items():
|
|
|
assert len(candidates) > 0
|
|
|
assert all(candidate.original_spec == spec for candidate in candidates)
|
|
|
|
|
|
def test_mutation_syntax_validation(self):
|
|
|
"""测试突变语法验证"""
|
|
|
valid_spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
invalid_spec = "void test(int x) { invalid_syntax }"
|
|
|
|
|
|
# 有效规范
|
|
|
valid_candidates = self.operators.generate_mutations(valid_spec, [MutationType.PREDICATE])
|
|
|
assert len(valid_candidates) > 0
|
|
|
|
|
|
# 无效规范应该抛出异常
|
|
|
with pytest.raises(ValidationError):
|
|
|
self.operators.generate_mutations(invalid_spec, [MutationType.PREDICATE])
|
|
|
|
|
|
def test_mutation_statistics(self):
|
|
|
"""测试突变统计"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
candidates = self.operators.generate_mutations(spec, [MutationType.PREDICATE])
|
|
|
|
|
|
stats = self.operators.get_mutation_statistics(candidates)
|
|
|
assert "total_mutations" in stats
|
|
|
assert "average_confidence" in stats
|
|
|
assert "mutation_type_distribution" in stats
|
|
|
assert stats["total_mutations"] == len(candidates)
|
|
|
|
|
|
def test_mutation_pattern_application(self):
|
|
|
"""测试突变模式应用"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
pattern = MutationPattern(
|
|
|
pattern=r"__CPROVER_assume\((.+?)\)",
|
|
|
replacement="__CPROVER_assert(\\1, \"assertion\")",
|
|
|
description="Assume to Assert"
|
|
|
)
|
|
|
|
|
|
result = self.operators.apply_mutation_pattern(spec, pattern)
|
|
|
assert "__CPROVER_assert" in result
|
|
|
assert "__CPROVER_assume" not in result
|
|
|
|
|
|
def test_context_aware_mutation(self):
|
|
|
"""测试上下文感知突变"""
|
|
|
spec = """
|
|
|
void complex_function(int *array, int size, int threshold) {
|
|
|
__CPROVER_assume(array != NULL);
|
|
|
__CPROVER_assume(size > 0 && size <= 100);
|
|
|
__CPROVER_assume(threshold > 0);
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
if (array[i] > threshold) {
|
|
|
// Process element
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
"""
|
|
|
|
|
|
candidates = self.operators.generate_mutations(
|
|
|
spec,
|
|
|
[MutationType.ARRAY_BOUNDS, MutationType.POINTER_VALIDITY]
|
|
|
)
|
|
|
|
|
|
assert len(candidates) > 0
|
|
|
# 验证上下文被保留
|
|
|
for candidate in candidates:
|
|
|
assert "complex_function" in candidate.mutated_spec
|
|
|
assert "array" in candidate.mutated_spec
|
|
|
assert "size" in candidate.mutated_spec
|
|
|
|
|
|
|
|
|
class TestSpecSelector:
|
|
|
"""SpecSelector类测试"""
|
|
|
|
|
|
def setup_method(self):
|
|
|
"""测试方法设置"""
|
|
|
self.selector = SpecSelector()
|
|
|
|
|
|
def test_init(self):
|
|
|
"""测试初始化"""
|
|
|
assert isinstance(self.selector.weights, SelectionWeights)
|
|
|
assert self.selector.selection_history == []
|
|
|
|
|
|
def test_weighted_random_selection(self):
|
|
|
"""测试加权随机选择"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Test mutation"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.6,
|
|
|
description="Boundary mutation"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
selected = self.selector.select_candidates(
|
|
|
candidates,
|
|
|
strategy=SelectionStrategy.WEIGHTED_RANDOM,
|
|
|
count=1
|
|
|
)
|
|
|
|
|
|
assert len(selected) == 1
|
|
|
assert selected[0] in candidates
|
|
|
|
|
|
def test_tournament_selection(self):
|
|
|
"""测试锦标赛选择"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.9,
|
|
|
description="High confidence"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.5,
|
|
|
description="Low confidence"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
selected = self.selector.select_candidates(
|
|
|
candidates,
|
|
|
strategy=SelectionStrategy.TOURNAMENT,
|
|
|
count=1
|
|
|
)
|
|
|
|
|
|
assert len(selected) == 1
|
|
|
# 更高置信度的候选者应该更可能被选中
|
|
|
|
|
|
def test_elite_selection(self):
|
|
|
"""测试精英选择"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.7,
|
|
|
description="Good mutation"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.9,
|
|
|
description="Better mutation"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="3",
|
|
|
mutation_type=MutationType.LOGICAL,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x > 0 || x < 10) { } }",
|
|
|
confidence=0.6,
|
|
|
description="Worse mutation"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
selected = self.selector.select_candidates(
|
|
|
candidates,
|
|
|
strategy=SelectionStrategy.ELITE,
|
|
|
count=2
|
|
|
)
|
|
|
|
|
|
assert len(selected) == 2
|
|
|
# 应该选择置信度最高的两个
|
|
|
selected_confidences = [c.confidence for c in selected]
|
|
|
assert sorted(selected_confidences, reverse=True) == selected_confidences
|
|
|
|
|
|
def test_adaptive_selection(self):
|
|
|
"""测试自适应选择"""
|
|
|
# 设置历史记录
|
|
|
self.selector.selection_history = [
|
|
|
SelectionHistory(
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
success_rate=0.8,
|
|
|
average_quality=0.7
|
|
|
),
|
|
|
SelectionHistory(
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
success_rate=0.4,
|
|
|
average_quality=0.5
|
|
|
)
|
|
|
]
|
|
|
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.6,
|
|
|
description="Predicate mutation"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.6,
|
|
|
description="Boundary mutation"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
selected = self.selector.select_candidates(
|
|
|
candidates,
|
|
|
strategy=SelectionStrategy.ADAPTIVE,
|
|
|
count=1
|
|
|
)
|
|
|
|
|
|
assert len(selected) == 1
|
|
|
# PREDICATE应该有更高概率被选中,因为历史成功率更高
|
|
|
|
|
|
def test_selection_with_constraints(self):
|
|
|
"""测试带约束的选择"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Predicate mutation"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.8,
|
|
|
description="Boundary mutation"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
# 设置最大数量约束
|
|
|
selected = self.selector.select_candidates(
|
|
|
candidates,
|
|
|
strategy=SelectionStrategy.WEIGHTED_RANDOM,
|
|
|
count=1,
|
|
|
max_count_per_type=1
|
|
|
)
|
|
|
|
|
|
assert len(selected) == 1
|
|
|
|
|
|
def test_diversity_optimization(self):
|
|
|
"""测试多样性优化"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Predicate mutation 1"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x >= 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Predicate mutation 2"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="3",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.8,
|
|
|
description="Boundary mutation"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
# 选择2个候选者,应该倾向于多样性
|
|
|
selected = self.selector.select_candidates(
|
|
|
candidates,
|
|
|
strategy=SelectionStrategy.WEIGHTED_RANDOM,
|
|
|
count=2,
|
|
|
optimize_diversity=True
|
|
|
)
|
|
|
|
|
|
assert len(selected) == 2
|
|
|
selected_types = {c.mutation_type for c in selected}
|
|
|
# 应该包含不同类型以增加多样性
|
|
|
assert len(selected_types) >= 1
|
|
|
|
|
|
def test_update_selection_history(self):
|
|
|
"""测试更新选择历史"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Predicate mutation"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
# 模拟选择过程
|
|
|
self.selector.update_selection_history(candidates, success=True)
|
|
|
|
|
|
assert len(self.selector.selection_history) > 0
|
|
|
history = self.selector.selection_history[-1]
|
|
|
assert history.mutation_type == MutationType.PREDICATE
|
|
|
|
|
|
def test_get_selection_statistics(self):
|
|
|
"""测试获取选择统计"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Predicate mutation"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.6,
|
|
|
description="Boundary mutation"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
stats = self.selector.get_selection_statistics(candidates)
|
|
|
assert "total_candidates" in stats
|
|
|
assert "average_confidence" in stats
|
|
|
assert "type_distribution" in stats
|
|
|
assert stats["total_candidates"] == len(candidates)
|
|
|
|
|
|
|
|
|
class TestQualityEvaluator:
|
|
|
"""QualityEvaluator类测试"""
|
|
|
|
|
|
def setup_method(self):
|
|
|
"""测试方法设置"""
|
|
|
self.evaluator = QualityEvaluator()
|
|
|
|
|
|
def test_init(self):
|
|
|
"""测试初始化"""
|
|
|
assert isinstance(self.evaluator.weights, EvaluationWeights)
|
|
|
|
|
|
def test_accuracy_evaluation(self):
|
|
|
"""测试准确性评估"""
|
|
|
candidate = MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Predicate mutation"
|
|
|
)
|
|
|
|
|
|
accuracy_score = self.evaluator.evaluate_accuracy(candidate)
|
|
|
assert 0.0 <= accuracy_score <= 1.0
|
|
|
|
|
|
def test_completeness_evaluation(self):
|
|
|
"""测试完整性评估"""
|
|
|
candidate = MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); __CPROVER_assert(x < 100, \"bounds\"); }",
|
|
|
confidence=0.8,
|
|
|
description="Complete mutation"
|
|
|
)
|
|
|
|
|
|
completeness_score = self.evaluator.evaluate_completeness(candidate)
|
|
|
assert 0.0 <= completeness_score <= 1.0
|
|
|
|
|
|
def test_verifiability_evaluation(self):
|
|
|
"""测试可验证性评估"""
|
|
|
candidate = MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Verifiable mutation"
|
|
|
)
|
|
|
|
|
|
verifiability_score = self.evaluator.evaluate_verifiability(candidate)
|
|
|
assert 0.0 <= verifiability_score <= 1.0
|
|
|
|
|
|
def test_stability_evaluation(self):
|
|
|
"""测试稳定性评估"""
|
|
|
candidate = MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Stable mutation"
|
|
|
)
|
|
|
|
|
|
stability_score = self.evaluator.evaluate_stability(candidate)
|
|
|
assert 0.0 <= stability_score <= 1.0
|
|
|
|
|
|
def test_efficiency_evaluation(self):
|
|
|
"""测试效率评估"""
|
|
|
candidate = MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Efficient mutation"
|
|
|
)
|
|
|
|
|
|
efficiency_score = self.evaluator.evaluate_efficiency(candidate)
|
|
|
assert 0.0 <= efficiency_score <= 1.0
|
|
|
|
|
|
def test_comprehensive_quality_evaluation(self):
|
|
|
"""测试全面质量评估"""
|
|
|
candidate = MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Comprehensive mutation"
|
|
|
)
|
|
|
|
|
|
quality_metrics = self.evaluator.evaluate_comprehensive_quality(candidate)
|
|
|
assert isinstance(quality_metrics, QualityMetrics)
|
|
|
assert hasattr(quality_metrics, 'overall_score')
|
|
|
assert 0.0 <= quality_metrics.overall_score <= 1.0
|
|
|
|
|
|
def test_evaluation_with_verification_results(self):
|
|
|
"""测试带验证结果的评估"""
|
|
|
candidate = MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Tested mutation"
|
|
|
)
|
|
|
|
|
|
verification_result = VerificationResult(
|
|
|
status=VerificationStatus.SUCCESSFUL,
|
|
|
verification_time=5.0,
|
|
|
memory_usage=1024,
|
|
|
is_successful=True
|
|
|
)
|
|
|
|
|
|
quality_metrics = self.evaluator.evaluate_with_verification(candidate, verification_result)
|
|
|
assert isinstance(quality_metrics, QualityMetrics)
|
|
|
# 成功的验证应该提高质量分数
|
|
|
assert quality_metrics.overall_score > 0.5
|
|
|
|
|
|
def test_batch_evaluation(self):
|
|
|
"""测试批量评估"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.8,
|
|
|
description="Mutation 1"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.6,
|
|
|
description="Mutation 2"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
batch_results = self.evaluator.evaluate_batch(candidates)
|
|
|
assert len(batch_results) == len(candidates)
|
|
|
for candidate, metrics in batch_results.items():
|
|
|
assert isinstance(metrics, QualityMetrics)
|
|
|
|
|
|
def test_quality_threshold_filtering(self):
|
|
|
"""测试质量阈值过滤"""
|
|
|
candidates = [
|
|
|
MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.9,
|
|
|
description="High quality"
|
|
|
),
|
|
|
MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.3,
|
|
|
description="Low quality"
|
|
|
)
|
|
|
]
|
|
|
|
|
|
filtered = self.evaluator.filter_by_quality_threshold(candidates, threshold=0.7)
|
|
|
assert len(filtered) == 1
|
|
|
assert filtered[0].confidence == 0.9
|
|
|
|
|
|
def test_quality_comparison(self):
|
|
|
"""测试质量比较"""
|
|
|
candidate1 = MutationCandidate(
|
|
|
id="1",
|
|
|
mutation_type=MutationType.PREDICATE,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { __CPROVER_assume(x > 0); }",
|
|
|
confidence=0.9,
|
|
|
description="High quality"
|
|
|
)
|
|
|
candidate2 = MutationCandidate(
|
|
|
id="2",
|
|
|
mutation_type=MutationType.BOUNDARY,
|
|
|
original_spec="void test(int x) { }",
|
|
|
mutated_spec="void test(int x) { if (x < 10) { } }",
|
|
|
confidence=0.5,
|
|
|
description="Medium quality"
|
|
|
)
|
|
|
|
|
|
comparison = self.evaluator.compare_quality(candidate1, candidate2)
|
|
|
assert comparison > 0 # candidate1 应该比 candidate2 好
|
|
|
|
|
|
|
|
|
class TestMutationEngine:
|
|
|
"""MutationEngine类测试"""
|
|
|
|
|
|
def setup_method(self):
|
|
|
"""测试方法设置"""
|
|
|
self.config = MutationConfig(
|
|
|
max_candidates_per_function=20,
|
|
|
max_selected_candidates=5,
|
|
|
quality_threshold=0.6
|
|
|
)
|
|
|
self.engine = MutationEngine(self.config)
|
|
|
|
|
|
def test_init(self):
|
|
|
"""测试初始化"""
|
|
|
assert self.engine.config == self.config
|
|
|
assert isinstance(self.engine.operators, CBMCMutationOperators)
|
|
|
assert isinstance(self.engine.selector, SpecSelector)
|
|
|
assert isinstance(self.engine.evaluator, QualityEvaluator)
|
|
|
|
|
|
def test_create_mutation_session(self):
|
|
|
"""测试创建突变会话"""
|
|
|
spec = "void test(int x) { }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
session = self.engine.create_mutation_session(spec, function_metadata)
|
|
|
assert isinstance(session, MutationSession)
|
|
|
assert session.original_spec == spec
|
|
|
assert session.function_metadata == function_metadata
|
|
|
assert session.session_id is not None
|
|
|
|
|
|
def test_exhaustive_mutation_strategy(self):
|
|
|
"""测试穷举突变策略"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
result = self.engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.EXHAUSTIVE
|
|
|
)
|
|
|
|
|
|
assert isinstance(result, MutationResult)
|
|
|
assert result.session_id is not None
|
|
|
assert len(result.selected_candidates) > 0
|
|
|
|
|
|
def test_heuristic_mutation_strategy(self):
|
|
|
"""测试启发式突变策略"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
result = self.engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.HEURISTIC
|
|
|
)
|
|
|
|
|
|
assert isinstance(result, MutationResult)
|
|
|
assert result.strategy == MutationStrategy.HEURISTIC
|
|
|
assert len(result.selected_candidates) <= self.config.max_selected_candidates
|
|
|
|
|
|
def test_adaptive_mutation_strategy(self):
|
|
|
"""测试自适应突变策略"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
result = self.engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.ADAPTIVE
|
|
|
)
|
|
|
|
|
|
assert isinstance(result, MutationResult)
|
|
|
assert result.strategy == MutationStrategy.ADAPTIVE
|
|
|
|
|
|
def test_targeted_mutation_strategy(self):
|
|
|
"""测试目标突变策略"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
target_types = [MutationType.PREDICATE]
|
|
|
|
|
|
result = self.engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.TARGETED,
|
|
|
target_mutation_types=target_types
|
|
|
)
|
|
|
|
|
|
assert isinstance(result, MutationResult)
|
|
|
assert result.strategy == MutationStrategy.TARGETED
|
|
|
# 所有选中的候选者应该是目标类型
|
|
|
for candidate in result.selected_candidates:
|
|
|
assert candidate.mutation_type in target_types
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
async def test_async_mutation_execution(self):
|
|
|
"""测试异步突变执行"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
result = await self.engine.execute_mutation_async(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.HEURISTIC
|
|
|
)
|
|
|
|
|
|
assert isinstance(result, MutationResult)
|
|
|
|
|
|
def test_batch_mutation_execution(self):
|
|
|
"""测试批量突变执行"""
|
|
|
specs = [
|
|
|
("void test1(int x) { __CPROVER_assume(x > 0); }", {"name": "test1", "parameters": [{"name": "x", "type": "int"}]}),
|
|
|
("void test2(int y) { if (y < 10) { } }", {"name": "test2", "parameters": [{"name": "y", "type": "int"}]})
|
|
|
]
|
|
|
|
|
|
results = self.engine.execute_batch_mutations(specs, strategy=MutationStrategy.HEURISTIC)
|
|
|
|
|
|
assert len(results) == len(specs)
|
|
|
for result in results:
|
|
|
assert isinstance(result, MutationResult)
|
|
|
|
|
|
def test_mutation_progress_tracking(self):
|
|
|
"""测试突变进度跟踪"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
progress_updates = []
|
|
|
def progress_callback(session_id, stage, progress, message):
|
|
|
progress_updates.append((session_id, stage, progress, message))
|
|
|
|
|
|
result = self.engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.HEURISTIC,
|
|
|
progress_callback=progress_callback
|
|
|
)
|
|
|
|
|
|
assert len(progress_updates) > 0
|
|
|
# 检查是否有不同阶段的进度更新
|
|
|
stages = [update[1] for update in progress_updates]
|
|
|
assert len(set(stages)) > 1
|
|
|
|
|
|
def test_mutation_error_handling(self):
|
|
|
"""测试突变错误处理"""
|
|
|
invalid_spec = "invalid syntax here"
|
|
|
|
|
|
with pytest.raises(MutationError):
|
|
|
self.engine.execute_mutation(
|
|
|
invalid_spec,
|
|
|
{"name": "test", "parameters": []},
|
|
|
strategy=MutationStrategy.HEURISTIC
|
|
|
)
|
|
|
|
|
|
def test_mutation_resource_constraints(self):
|
|
|
"""测试突变资源约束"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
# 设置严格的约束
|
|
|
constrained_config = MutationConfig(
|
|
|
max_candidates_per_function=2,
|
|
|
max_selected_candidates=1,
|
|
|
quality_threshold=0.9
|
|
|
)
|
|
|
engine = MutationEngine(constrained_config)
|
|
|
|
|
|
result = engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.HEURISTIC
|
|
|
)
|
|
|
|
|
|
assert len(result.selected_candidates) <= constrained_config.max_selected_candidates
|
|
|
|
|
|
def test_mutation_session_management(self):
|
|
|
"""测试突变会话管理"""
|
|
|
# 创建多个会话
|
|
|
spec1 = "void test1(int x) { }"
|
|
|
spec2 = "void test2(int y) { }"
|
|
|
|
|
|
session1 = self.engine.create_mutation_session(spec1, {"name": "test1", "parameters": []})
|
|
|
session2 = self.engine.create_mutation_session(spec2, {"name": "test2", "parameters": []})
|
|
|
|
|
|
# 获取活跃会话
|
|
|
active_sessions = self.engine.get_active_sessions()
|
|
|
assert len(active_sessions) >= 2
|
|
|
assert session1.session_id in [s.session_id for s in active_sessions]
|
|
|
assert session2.session_id in [s.session_id for s in active_sessions]
|
|
|
|
|
|
# 清理会话
|
|
|
self.engine.cleanup_session(session1.session_id)
|
|
|
active_sessions_after = self.engine.get_active_sessions()
|
|
|
assert session1.session_id not in [s.session_id for s in active_sessions_after]
|
|
|
|
|
|
def test_mutation_statistics(self):
|
|
|
"""测试突变统计"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
result = self.engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.HEURISTIC
|
|
|
)
|
|
|
|
|
|
stats = self.engine.get_mutation_statistics()
|
|
|
assert "total_sessions" in stats
|
|
|
assert "average_candidates_per_session" in stats
|
|
|
assert "success_rate" in stats
|
|
|
|
|
|
|
|
|
class TestMutateModuleIntegration:
|
|
|
"""Mutate模块集成测试"""
|
|
|
|
|
|
def test_complete_mutation_workflow(self):
|
|
|
"""测试完整突变工作流"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
# 创建突变引擎
|
|
|
config = MutationConfig(
|
|
|
max_candidates_per_function=10,
|
|
|
max_selected_candidates=3,
|
|
|
quality_threshold=0.6
|
|
|
)
|
|
|
engine = MutationEngine(config)
|
|
|
|
|
|
# 执行突变
|
|
|
result = engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.HEURISTIC
|
|
|
)
|
|
|
|
|
|
# 验证结果
|
|
|
assert isinstance(result, MutationResult)
|
|
|
assert result.session_id is not None
|
|
|
assert len(result.all_candidates) > 0
|
|
|
assert len(result.selected_candidates) > 0
|
|
|
assert len(result.selected_candidates) <= config.max_selected_candidates
|
|
|
|
|
|
# 验证选中的候选者质量
|
|
|
for candidate in result.selected_candidates:
|
|
|
assert candidate.confidence >= config.quality_threshold
|
|
|
|
|
|
def test_mutation_with_verification_integration(self):
|
|
|
"""测试与验证的集成"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
config = MutationConfig(
|
|
|
max_candidates_per_function=5,
|
|
|
max_selected_candidates=2,
|
|
|
quality_threshold=0.5
|
|
|
)
|
|
|
engine = MutationEngine(config)
|
|
|
|
|
|
# 模拟验证结果
|
|
|
def mock_verify(candidate):
|
|
|
# 模拟一些候选者验证成功,一些失败
|
|
|
if "assume" in candidate.mutated_spec:
|
|
|
return VerificationResult(
|
|
|
status=VerificationStatus.SUCCESSFUL,
|
|
|
verification_time=2.0,
|
|
|
memory_usage=512,
|
|
|
is_successful=True
|
|
|
)
|
|
|
else:
|
|
|
return VerificationResult(
|
|
|
status=VerificationStatus.FAILED,
|
|
|
verification_time=1.0,
|
|
|
memory_usage=256,
|
|
|
is_successful=False
|
|
|
)
|
|
|
|
|
|
result = engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.HEURISTIC,
|
|
|
verification_callback=mock_verify
|
|
|
)
|
|
|
|
|
|
assert isinstance(result, MutationResult)
|
|
|
# 验证成功的候选者应该被优先选择
|
|
|
|
|
|
def test_error_handling_integration(self):
|
|
|
"""测试错误处理集成"""
|
|
|
# 测试无效输入
|
|
|
with pytest.raises(MutationError):
|
|
|
engine = MutationEngine(MutationConfig())
|
|
|
engine.execute_mutation("", {}, strategy=MutationStrategy.HEURISTIC)
|
|
|
|
|
|
# 测试配置错误
|
|
|
with pytest.raises(ResourceError):
|
|
|
invalid_config = MutationConfig(
|
|
|
max_candidates_per_function=-1,
|
|
|
max_selected_candidates=-1
|
|
|
)
|
|
|
engine = MutationEngine(invalid_config)
|
|
|
|
|
|
def test_performance_considerations(self):
|
|
|
"""测试性能考虑"""
|
|
|
spec = "void test(int x) { __CPROVER_assume(x > 0); }"
|
|
|
function_metadata = {"name": "test", "parameters": [{"name": "x", "type": "int"}]}
|
|
|
|
|
|
config = MutationConfig(
|
|
|
max_candidates_per_function=50, # 较大数量测试性能
|
|
|
max_selected_candidates=10,
|
|
|
quality_threshold=0.3
|
|
|
)
|
|
|
engine = MutationEngine(config)
|
|
|
|
|
|
# 测试执行时间
|
|
|
import time
|
|
|
start_time = time.time()
|
|
|
result = engine.execute_mutation(
|
|
|
spec,
|
|
|
function_metadata,
|
|
|
strategy=MutationStrategy.HEURISTIC
|
|
|
)
|
|
|
end_time = time.time()
|
|
|
|
|
|
execution_time = end_time - start_time
|
|
|
assert execution_time < 10.0 # 应该在合理时间内完成
|
|
|
|
|
|
assert isinstance(result, MutationResult)
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
pytest.main([__file__, "-v"]) |