|
# retoor <retoor@molodetz.nl>
|
|
|
|
import pytest
|
|
from rp.core.project_analyzer import ProjectAnalyzer, AnalysisResult
|
|
|
|
|
|
class TestProjectAnalyzer:
|
|
def setup_method(self):
|
|
self.analyzer = ProjectAnalyzer()
|
|
|
|
def test_analyze_requirements_valid_code(self):
|
|
code_content = """
|
|
import json
|
|
import requests
|
|
from pydantic import BaseModel
|
|
|
|
class User(BaseModel):
|
|
name: str
|
|
age: int
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content=code_content,
|
|
)
|
|
|
|
assert isinstance(result, AnalysisResult)
|
|
assert result.language == 'python'
|
|
assert 'requests' in result.dependencies
|
|
assert 'pydantic' in result.dependencies
|
|
|
|
def test_pydantic_breaking_change_detection(self):
|
|
code_content = """
|
|
from pydantic import BaseSettings
|
|
|
|
class Config(BaseSettings):
|
|
api_key: str
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content=code_content,
|
|
)
|
|
|
|
assert not result.valid
|
|
assert any('BaseSettings' in e for e in result.errors)
|
|
|
|
def test_shell_command_validation_valid(self):
|
|
commands = [
|
|
"pip install fastapi",
|
|
"mkdir -p /tmp/test",
|
|
"python script.py",
|
|
]
|
|
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
commands=commands,
|
|
)
|
|
|
|
valid_commands = [c for c in result.shell_commands if c['valid']]
|
|
assert len(valid_commands) > 0
|
|
|
|
def test_shell_command_validation_invalid_brace_expansion(self):
|
|
commands = [
|
|
"mkdir -p {app/{api,database,model)",
|
|
]
|
|
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
commands=commands,
|
|
)
|
|
|
|
assert not result.valid
|
|
assert any('brace' in e.lower() or 'syntax' in e.lower() for e in result.errors)
|
|
|
|
def test_python_version_detection(self):
|
|
code_with_walrus = """
|
|
if (x := 10) > 5:
|
|
print(x)
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content=code_with_walrus,
|
|
)
|
|
|
|
version_parts = result.language_version.split('.')
|
|
assert int(version_parts[1]) >= 8
|
|
|
|
def test_directory_structure_planning(self):
|
|
spec_content = """
|
|
Create the following structure:
|
|
- directory: src/app
|
|
- directory: src/tests
|
|
- file: src/main.py
|
|
- file: src/config.py
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content=spec_content,
|
|
)
|
|
|
|
assert len(result.file_structure) > 1
|
|
assert '.' in result.file_structure
|
|
|
|
def test_import_compatibility_check(self):
|
|
dependencies = {'pydantic': '2.0', 'fastapi': '0.100'}
|
|
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content="",
|
|
)
|
|
|
|
assert isinstance(result.import_compatibility, dict)
|
|
|
|
def test_token_budget_calculation(self):
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content="import json\nimport requests\n",
|
|
commands=["pip install -r requirements.txt"],
|
|
)
|
|
|
|
assert result.estimated_tokens > 0
|
|
|
|
def test_stdlib_detection(self):
|
|
code = """
|
|
import os
|
|
import sys
|
|
import json
|
|
import custom_module
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content=code,
|
|
)
|
|
|
|
assert 'custom_module' in result.dependencies
|
|
assert 'json' not in result.dependencies or len(result.dependencies) == 1
|
|
|
|
def test_optional_dependencies_detection(self):
|
|
code = """
|
|
import structlog
|
|
import uvicorn
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content=code,
|
|
)
|
|
|
|
assert 'structlog' in result.dependencies or len(result.warnings) > 0
|
|
|
|
def test_fastapi_breaking_change_detection(self):
|
|
code = """
|
|
from fastapi.middleware.gzip import GZIPMiddleware
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="test.txt",
|
|
code_content=code,
|
|
)
|
|
|
|
assert not result.valid
|
|
assert any('GZIPMiddleware' in str(e) or 'fastapi' in str(e).lower() for e in result.errors)
|
|
|
|
|
|
class TestCLanguageAnalyzer:
|
|
def setup_method(self):
|
|
self.analyzer = ProjectAnalyzer()
|
|
|
|
def test_detect_c_language(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
int main(int argc, char *argv[]) {
|
|
printf("Hello, World!\\n");
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert result.language == 'c'
|
|
|
|
def test_c_standard_headers_detection(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
int main() {
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert 'stdio.h' in result.dependencies
|
|
assert result.dependencies['stdio.h'] == 'stdlib'
|
|
assert result.dependencies['math.h'] == 'stdlib'
|
|
|
|
def test_c_posix_headers_detection(self):
|
|
c_code = """
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <sys/socket.h>
|
|
|
|
int main() {
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert 'unistd.h' in result.dependencies
|
|
assert result.dependencies['unistd.h'] == 'posix'
|
|
assert any('POSIX' in w for w in result.warnings)
|
|
|
|
def test_c_local_headers_detection(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
#include "myheader.h"
|
|
#include "utils/helper.h"
|
|
|
|
int main() {
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert 'myheader.h' in result.dependencies
|
|
assert result.dependencies['myheader.h'] == 'local'
|
|
|
|
def test_c_external_library_headers(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
#include <curl/curl.h>
|
|
#include <openssl/ssl.h>
|
|
|
|
int main() {
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert 'curl/curl.h' in result.dependencies
|
|
assert result.dependencies['curl/curl.h'] == 'curl'
|
|
assert any('curl' in w for w in result.warnings)
|
|
|
|
def test_c_standard_detection_c99(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
for (int i = 0; i < 10; i++) {
|
|
printf("%d\\n", i);
|
|
}
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert result.language_version == 'c99'
|
|
|
|
def test_c_standard_detection_c11(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
#include <stdatomic.h>
|
|
|
|
int main() {
|
|
_Static_assert(sizeof(int) >= 4, "int must be at least 4 bytes");
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert result.language_version == 'c11'
|
|
|
|
def test_c_standard_detection_gnu(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
typeof(5) x = 10;
|
|
printf("%d\\n", x);
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert 'gnu' in result.language_version
|
|
|
|
def test_c_compiler_flags_suggestion(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <pthread.h>
|
|
|
|
int main() {
|
|
pthread_t thread;
|
|
double x = sqrt(2.0);
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert '-lm' in result.compiler_flags
|
|
assert '-pthread' in result.compiler_flags
|
|
assert any('-std=' in f for f in result.compiler_flags)
|
|
assert '-Wall' in result.compiler_flags
|
|
|
|
def test_c_valid_analysis_no_errors(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
printf("Hello\\n");
|
|
return 0;
|
|
}
|
|
"""
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
)
|
|
|
|
assert result.valid
|
|
assert len(result.errors) == 0
|
|
|
|
def test_c_shell_commands_validation(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
int main() { return 0; }
|
|
"""
|
|
commands = [
|
|
"gcc -o main main.c",
|
|
"make clean",
|
|
"./main",
|
|
]
|
|
|
|
result = self.analyzer.analyze_requirements(
|
|
spec_file="main.c",
|
|
code_content=c_code,
|
|
commands=commands,
|
|
)
|
|
|
|
valid_commands = [c for c in result.shell_commands if c['valid']]
|
|
assert len(valid_commands) == 3
|
|
|
|
|
|
class TestLanguageDetection:
|
|
def setup_method(self):
|
|
self.analyzer = ProjectAnalyzer()
|
|
|
|
def test_detect_python_from_content(self):
|
|
python_code = """
|
|
def hello():
|
|
print("Hello, World!")
|
|
|
|
if __name__ == "__main__":
|
|
hello()
|
|
"""
|
|
lang = self.analyzer.detect_language(python_code)
|
|
assert lang == 'python'
|
|
|
|
def test_detect_c_from_content(self):
|
|
c_code = """
|
|
#include <stdio.h>
|
|
|
|
int main(int argc, char *argv[]) {
|
|
printf("Hello\\n");
|
|
return 0;
|
|
}
|
|
"""
|
|
lang = self.analyzer.detect_language(c_code)
|
|
assert lang == 'c'
|
|
|
|
def test_detect_cpp_from_content(self):
|
|
cpp_code = """
|
|
#include <iostream>
|
|
|
|
int main() {
|
|
std::cout << "Hello" << std::endl;
|
|
return 0;
|
|
}
|
|
"""
|
|
lang = self.analyzer.detect_language(cpp_code)
|
|
assert lang == 'cpp'
|
|
|
|
def test_detect_rust_from_content(self):
|
|
rust_code = """
|
|
fn main() {
|
|
let x = 5;
|
|
println!("x = {}", x);
|
|
}
|
|
"""
|
|
lang = self.analyzer.detect_language(rust_code)
|
|
assert lang == 'rust'
|
|
|
|
def test_detect_go_from_content(self):
|
|
go_code = """
|
|
package main
|
|
|
|
import "fmt"
|
|
|
|
func main() {
|
|
fmt.Println("Hello")
|
|
}
|
|
"""
|
|
lang = self.analyzer.detect_language(go_code)
|
|
assert lang == 'go'
|
|
|
|
def test_detect_javascript_from_content(self):
|
|
js_code = """
|
|
const express = require('express');
|
|
|
|
function hello() {
|
|
console.log("Hello");
|
|
}
|
|
|
|
export default hello;
|
|
"""
|
|
lang = self.analyzer.detect_language(js_code)
|
|
assert lang == 'javascript'
|
|
|
|
def test_detect_language_from_file_extension(self):
|
|
lang = self.analyzer.detect_language("", "main.c")
|
|
assert lang == 'c'
|
|
|
|
lang = self.analyzer.detect_language("", "app.py")
|
|
assert lang == 'python'
|
|
|
|
def test_detect_unknown_language(self):
|
|
weird_content = "some random text without any language patterns"
|
|
lang = self.analyzer.detect_language(weird_content)
|
|
assert lang == 'unknown'
|