mirror of
https://github.com/johndoe6345789/WizardMerge.git
synced 2026-04-25 14:14:59 +00:00
- Enhanced context_analyzer to detect TypeScript patterns (interfaces, types, enums, arrow functions, async functions) - Updated risk_analyzer with TypeScript-specific critical patterns (as any, @ts-ignore, dangerouslySetInnerHTML, etc.) - Added has_typescript_interface_changes() to detect type definition changes - Added is_package_lock_file() to identify lock files - Created comprehensive tests for TypeScript functionality - All 46 tests passing Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
269 lines
7.9 KiB
C++
269 lines
7.9 KiB
C++
/**
|
|
* @file test_risk_analyzer.cpp
|
|
* @brief Unit tests for risk analysis module
|
|
*/
|
|
|
|
#include "wizardmerge/analysis/risk_analyzer.h"
|
|
#include <gtest/gtest.h>
|
|
|
|
using namespace wizardmerge::analysis;
|
|
|
|
/**
|
|
* Test risk level to string conversion
|
|
*/
|
|
TEST(RiskAnalyzerTest, RiskLevelToString) {
|
|
EXPECT_EQ(risk_level_to_string(RiskLevel::LOW), "low");
|
|
EXPECT_EQ(risk_level_to_string(RiskLevel::MEDIUM), "medium");
|
|
EXPECT_EQ(risk_level_to_string(RiskLevel::HIGH), "high");
|
|
EXPECT_EQ(risk_level_to_string(RiskLevel::CRITICAL), "critical");
|
|
}
|
|
|
|
/**
|
|
* Test basic risk analysis for "ours"
|
|
*/
|
|
TEST(RiskAnalyzerTest, BasicRiskAnalysisOurs) {
|
|
std::vector<std::string> base = {"int x = 10;"};
|
|
std::vector<std::string> ours = {"int x = 20;"};
|
|
std::vector<std::string> theirs = {"int x = 30;"};
|
|
|
|
auto risk = analyze_risk_ours(base, ours, theirs);
|
|
|
|
EXPECT_TRUE(risk.level == RiskLevel::LOW || risk.level == RiskLevel::MEDIUM);
|
|
EXPECT_GE(risk.confidence_score, 0.0);
|
|
EXPECT_LE(risk.confidence_score, 1.0);
|
|
EXPECT_FALSE(risk.recommendations.empty());
|
|
}
|
|
|
|
/**
|
|
* Test basic risk analysis for "theirs"
|
|
*/
|
|
TEST(RiskAnalyzerTest, BasicRiskAnalysisTheirs) {
|
|
std::vector<std::string> base = {"int x = 10;"};
|
|
std::vector<std::string> ours = {"int x = 20;"};
|
|
std::vector<std::string> theirs = {"int x = 30;"};
|
|
|
|
auto risk = analyze_risk_theirs(base, ours, theirs);
|
|
|
|
EXPECT_TRUE(risk.level == RiskLevel::LOW || risk.level == RiskLevel::MEDIUM);
|
|
EXPECT_GE(risk.confidence_score, 0.0);
|
|
EXPECT_LE(risk.confidence_score, 1.0);
|
|
EXPECT_FALSE(risk.recommendations.empty());
|
|
}
|
|
|
|
/**
|
|
* Test risk analysis for "both" (concatenation)
|
|
*/
|
|
TEST(RiskAnalyzerTest, RiskAnalysisBoth) {
|
|
std::vector<std::string> base = {"int x = 10;"};
|
|
std::vector<std::string> ours = {"int x = 20;"};
|
|
std::vector<std::string> theirs = {"int x = 30;"};
|
|
|
|
auto risk = analyze_risk_both(base, ours, theirs);
|
|
|
|
// "Both" strategy should typically have medium or higher risk
|
|
EXPECT_TRUE(risk.level >= RiskLevel::MEDIUM);
|
|
EXPECT_GE(risk.confidence_score, 0.0);
|
|
EXPECT_LE(risk.confidence_score, 1.0);
|
|
EXPECT_FALSE(risk.recommendations.empty());
|
|
}
|
|
|
|
/**
|
|
* Test critical pattern detection
|
|
*/
|
|
TEST(RiskAnalyzerTest, DetectCriticalPatterns) {
|
|
std::vector<std::string> safe_code = {"int x = 10;", "return x;"};
|
|
std::vector<std::string> unsafe_code = {"delete ptr;", "system(\"rm -rf /\");"};
|
|
|
|
EXPECT_FALSE(contains_critical_patterns(safe_code));
|
|
EXPECT_TRUE(contains_critical_patterns(unsafe_code));
|
|
}
|
|
|
|
/**
|
|
* Test API signature change detection
|
|
*/
|
|
TEST(RiskAnalyzerTest, DetectAPISignatureChanges) {
|
|
std::vector<std::string> base_sig = {"void myFunction(int x) {"};
|
|
std::vector<std::string> modified_sig = {"void myFunction(int x, int y) {"};
|
|
std::vector<std::string> same_sig = {"void myFunction(int x) {"};
|
|
|
|
EXPECT_TRUE(has_api_signature_changes(base_sig, modified_sig));
|
|
EXPECT_FALSE(has_api_signature_changes(base_sig, same_sig));
|
|
}
|
|
|
|
/**
|
|
* Test high risk for large changes
|
|
*/
|
|
TEST(RiskAnalyzerTest, HighRiskForLargeChanges) {
|
|
std::vector<std::string> base = {"line1"};
|
|
std::vector<std::string> ours;
|
|
std::vector<std::string> theirs = {"line1"};
|
|
|
|
// Create large change in ours
|
|
for (int i = 0; i < 15; ++i) {
|
|
ours.push_back("changed_line_" + std::to_string(i));
|
|
}
|
|
|
|
auto risk = analyze_risk_ours(base, ours, theirs);
|
|
|
|
// Should detect significant changes
|
|
EXPECT_TRUE(risk.level >= RiskLevel::MEDIUM);
|
|
EXPECT_FALSE(risk.risk_factors.empty());
|
|
}
|
|
|
|
/**
|
|
* Test risk with critical patterns
|
|
*/
|
|
TEST(RiskAnalyzerTest, CriticalPatternsIncreaseRisk) {
|
|
std::vector<std::string> base = {"int x = 10;"};
|
|
std::vector<std::string> ours = {"delete database;", "eval(user_input);"};
|
|
std::vector<std::string> theirs = {"int x = 10;"};
|
|
|
|
auto risk = analyze_risk_ours(base, ours, theirs);
|
|
|
|
EXPECT_TRUE(risk.level >= RiskLevel::HIGH);
|
|
EXPECT_TRUE(risk.affects_critical_section);
|
|
EXPECT_FALSE(risk.risk_factors.empty());
|
|
}
|
|
|
|
/**
|
|
* Test risk factors are populated
|
|
*/
|
|
TEST(RiskAnalyzerTest, RiskFactorsPopulated) {
|
|
std::vector<std::string> base = {"line1", "line2", "line3"};
|
|
std::vector<std::string> ours = {"changed1", "changed2", "changed3"};
|
|
std::vector<std::string> theirs = {"line1", "line2", "line3"};
|
|
|
|
auto risk = analyze_risk_ours(base, ours, theirs);
|
|
|
|
// Should have some analysis results
|
|
EXPECT_TRUE(!risk.recommendations.empty() || !risk.risk_factors.empty());
|
|
}
|
|
|
|
/**
|
|
* Test TypeScript interface change detection
|
|
*/
|
|
TEST(RiskAnalyzerTest, TypeScriptInterfaceChangesDetected) {
|
|
std::vector<std::string> base = {
|
|
"interface User {",
|
|
" name: string;",
|
|
"}"
|
|
};
|
|
std::vector<std::string> modified = {
|
|
"interface User {",
|
|
" name: string;",
|
|
" age: number;",
|
|
"}"
|
|
};
|
|
|
|
EXPECT_TRUE(has_typescript_interface_changes(base, modified));
|
|
}
|
|
|
|
/**
|
|
* Test TypeScript type alias change detection
|
|
*/
|
|
TEST(RiskAnalyzerTest, TypeScriptTypeChangesDetected) {
|
|
std::vector<std::string> base = {
|
|
"type Status = 'pending' | 'approved';"
|
|
};
|
|
std::vector<std::string> modified = {
|
|
"type Status = 'pending' | 'approved' | 'rejected';"
|
|
};
|
|
|
|
EXPECT_TRUE(has_typescript_interface_changes(base, modified));
|
|
}
|
|
|
|
/**
|
|
* Test TypeScript enum change detection
|
|
*/
|
|
TEST(RiskAnalyzerTest, TypeScriptEnumChangesDetected) {
|
|
std::vector<std::string> base = {
|
|
"enum Color {",
|
|
" Red,",
|
|
" Green",
|
|
"}"
|
|
};
|
|
std::vector<std::string> modified = {
|
|
"enum Color {",
|
|
" Red,",
|
|
" Green,",
|
|
" Blue",
|
|
"}"
|
|
};
|
|
|
|
EXPECT_TRUE(has_typescript_interface_changes(base, modified));
|
|
}
|
|
|
|
/**
|
|
* Test package-lock.json file detection
|
|
*/
|
|
TEST(RiskAnalyzerTest, PackageLockFileDetection) {
|
|
EXPECT_TRUE(is_package_lock_file("package-lock.json"));
|
|
EXPECT_TRUE(is_package_lock_file("path/to/package-lock.json"));
|
|
EXPECT_TRUE(is_package_lock_file("yarn.lock"));
|
|
EXPECT_TRUE(is_package_lock_file("pnpm-lock.yaml"));
|
|
EXPECT_TRUE(is_package_lock_file("bun.lockb"));
|
|
EXPECT_FALSE(is_package_lock_file("package.json"));
|
|
EXPECT_FALSE(is_package_lock_file("src/index.ts"));
|
|
}
|
|
|
|
/**
|
|
* Test TypeScript critical patterns detection
|
|
*/
|
|
TEST(RiskAnalyzerTest, TypeScriptCriticalPatternsDetected) {
|
|
std::vector<std::string> code_with_ts_issues = {
|
|
"const user = data as any;",
|
|
"// @ts-ignore",
|
|
"element.innerHTML = userInput;",
|
|
"localStorage.setItem('password', pwd);"
|
|
};
|
|
|
|
EXPECT_TRUE(contains_critical_patterns(code_with_ts_issues));
|
|
}
|
|
|
|
/**
|
|
* Test TypeScript safe code doesn't trigger false positives
|
|
*/
|
|
TEST(RiskAnalyzerTest, TypeScriptSafeCodeNoFalsePositives) {
|
|
std::vector<std::string> safe_code = {
|
|
"const user: User = { name: 'John', age: 30 };",
|
|
"function greet(name: string): string {",
|
|
" return `Hello, ${name}`;",
|
|
"}"
|
|
};
|
|
|
|
EXPECT_FALSE(contains_critical_patterns(safe_code));
|
|
}
|
|
|
|
/**
|
|
* Test risk analysis includes TypeScript interface changes
|
|
*/
|
|
TEST(RiskAnalyzerTest, RiskAnalysisIncludesTypeScriptChanges) {
|
|
std::vector<std::string> base = {
|
|
"interface User {",
|
|
" name: string;",
|
|
"}"
|
|
};
|
|
std::vector<std::string> ours = {
|
|
"interface User {",
|
|
" name: string;",
|
|
" email: string;",
|
|
"}"
|
|
};
|
|
std::vector<std::string> theirs = base;
|
|
|
|
auto risk = analyze_risk_ours(base, ours, theirs);
|
|
|
|
EXPECT_TRUE(risk.has_api_changes);
|
|
EXPECT_TRUE(risk.level >= RiskLevel::MEDIUM);
|
|
|
|
// Check if TypeScript-related risk factor is mentioned
|
|
bool has_ts_risk = false;
|
|
for (const auto& factor : risk.risk_factors) {
|
|
if (factor.find("TypeScript") != std::string::npos) {
|
|
has_ts_risk = true;
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(has_ts_risk);
|
|
}
|