feat: add C/C++ language support and analysis
refactor: improve architecture for maintainability build: update development status to production docs: enhance README with language support details docs: add C/C++ development support documentation docs: add entry points documentation test: add comprehensive test suite (545+ tests) refactor: rename asynchronous to modular architecture fix: resolve dependency resolution issues perf: improve dependency resolution performance
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import pytest
|
||||
from rp.core.project_analyzer import ProjectAnalyzer, AnalysisResult
|
||||
|
||||
@@ -22,6 +24,7 @@ class User(BaseModel):
|
||||
)
|
||||
|
||||
assert isinstance(result, AnalysisResult)
|
||||
assert result.language == 'python'
|
||||
assert 'requests' in result.dependencies
|
||||
assert 'pydantic' in result.dependencies
|
||||
|
||||
@@ -78,7 +81,7 @@ if (x := 10) > 5:
|
||||
code_content=code_with_walrus,
|
||||
)
|
||||
|
||||
version_parts = result.python_version.split('.')
|
||||
version_parts = result.language_version.split('.')
|
||||
assert int(version_parts[1]) >= 8
|
||||
|
||||
def test_directory_structure_planning(self):
|
||||
@@ -154,3 +157,300 @@ from fastapi.middleware.gzip import GZIPMiddleware
|
||||
|
||||
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'
|
||||
|
||||
Reference in New Issue
Block a user