Rthur2003 commited on
Commit
8bcdcab
·
1 Parent(s): 4ec07a1

fix: update analysis and commend endpoints with additional tests and default values

Browse files
app/routes/analyze.py CHANGED
@@ -32,7 +32,7 @@ class AnalysisFeatures(BaseModel):
32
  spectralRegularity: float = 0.5
33
  temporalPatterns: float = 0.5
34
  harmonicStructure: float = 0.5
35
- artificialIndicators: List[str] = []
36
 
37
 
38
  class AudioInfo(BaseModel):
@@ -62,8 +62,8 @@ class AnalyzeResponse(BaseModel):
62
  """Response model for analysis endpoint."""
63
 
64
  result: Optional[AnalysisResult] = None
65
- warnings: List[str] = []
66
- errors: List[str] = []
67
 
68
 
69
  @router.post("/api/analyze", response_model=AnalyzeResponse)
 
32
  spectralRegularity: float = 0.5
33
  temporalPatterns: float = 0.5
34
  harmonicStructure: float = 0.5
35
+ artificialIndicators: List[str] = Field(default_factory=list)
36
 
37
 
38
  class AudioInfo(BaseModel):
 
62
  """Response model for analysis endpoint."""
63
 
64
  result: Optional[AnalysisResult] = None
65
+ warnings: List[str] = Field(default_factory=list)
66
+ errors: List[str] = Field(default_factory=list)
67
 
68
 
69
  @router.post("/api/analyze", response_model=AnalyzeResponse)
tests/test_analyze.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for /api/analyze endpoint."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import io
6
+
7
+ from fastapi.testclient import TestClient
8
+
9
+
10
+ def test_analyze_missing_source_type(client: TestClient) -> None:
11
+ """Analyze should reject a request without sourceType."""
12
+ response = client.post("/api/analyze")
13
+ assert response.status_code == 422
14
+
15
+
16
+ def test_analyze_invalid_source_type(client: TestClient) -> None:
17
+ """Analyze should return error for unknown sourceType."""
18
+ response = client.post(
19
+ "/api/analyze",
20
+ data={"sourceType": "unknown"},
21
+ )
22
+ assert response.status_code == 200
23
+ data = response.json()
24
+ assert "invalid_source_type" in data["errors"]
25
+ assert data["result"] is None
26
+
27
+
28
+ def test_analyze_unsupported_source(client: TestClient) -> None:
29
+ """Analyze should return unsupported_source for spotify/apple."""
30
+ for source in ("spotify", "apple"):
31
+ response = client.post(
32
+ "/api/analyze",
33
+ data={"sourceType": source},
34
+ )
35
+ assert response.status_code == 200
36
+ data = response.json()
37
+ assert "unsupported_source" in data["errors"]
38
+
39
+
40
+ def test_analyze_youtube_missing_url(client: TestClient) -> None:
41
+ """Analyze youtube without url should return missing_url error."""
42
+ response = client.post(
43
+ "/api/analyze",
44
+ data={"sourceType": "youtube"},
45
+ )
46
+ assert response.status_code == 200
47
+ data = response.json()
48
+ assert "missing_url" in data["errors"]
49
+
50
+
51
+ def test_analyze_file_missing_file(client: TestClient) -> None:
52
+ """Analyze file without upload should return missing_file error."""
53
+ response = client.post(
54
+ "/api/analyze",
55
+ data={"sourceType": "file"},
56
+ )
57
+ assert response.status_code == 200
58
+ data = response.json()
59
+ assert "missing_file" in data["errors"]
60
+
61
+
62
+ def test_analyze_file_invalid_type(client: TestClient) -> None:
63
+ """Analyze should reject non-audio file."""
64
+ fake_file = io.BytesIO(b"not audio content " * 100)
65
+ response = client.post(
66
+ "/api/analyze",
67
+ data={"sourceType": "file"},
68
+ files={"file": ("test.txt", fake_file, "text/plain")},
69
+ )
70
+ assert response.status_code == 200
71
+ data = response.json()
72
+ assert "invalid_file_type" in data["errors"]
73
+
74
+
75
+ def test_analyze_file_too_small(client: TestClient) -> None:
76
+ """Analyze should reject files smaller than 1KB."""
77
+ tiny_file = io.BytesIO(b"\x00" * 100)
78
+ response = client.post(
79
+ "/api/analyze",
80
+ data={"sourceType": "file"},
81
+ files={"file": ("tiny.wav", tiny_file, "audio/wav")},
82
+ )
83
+ assert response.status_code == 200
84
+ data = response.json()
85
+ assert "file_too_small" in data["errors"]
86
+
87
+
88
+ def test_analyze_file_happy_path(client: TestClient) -> None:
89
+ """Analyze with a valid audio file should return a preview result."""
90
+ audio_content = b"\x00" * 2048
91
+ fake_audio = io.BytesIO(audio_content)
92
+ response = client.post(
93
+ "/api/analyze",
94
+ data={"sourceType": "file"},
95
+ files={"file": ("test.wav", fake_audio, "audio/wav")},
96
+ )
97
+ assert response.status_code == 200
98
+ data = response.json()
99
+ assert data["result"] is not None
100
+ result = data["result"]
101
+ assert "isAIGenerated" in result
102
+ assert "confidence" in result
103
+ assert result["analysisMode"] == "preview"
104
+ assert result["decisionSource"] == "preview"
tests/test_commend.py CHANGED
@@ -15,6 +15,15 @@ def test_commend_health(client: TestClient) -> None:
15
  assert "youtubeConfigured" in data
16
 
17
 
 
 
 
 
 
 
 
 
 
18
  def test_commend_generate_rejects_invalid_url(client: TestClient) -> None:
19
  """Generate endpoint should reject a non-YouTube URL."""
20
  response = client.post(
@@ -25,4 +34,30 @@ def test_commend_generate_rejects_invalid_url(client: TestClient) -> None:
25
  "style": "supportive",
26
  },
27
  )
28
- assert response.status_code in (400, 422)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  assert "youtubeConfigured" in data
16
 
17
 
18
+ def test_commend_styles(client: TestClient) -> None:
19
+ """Styles endpoint should return available comment styles."""
20
+ response = client.get("/api/commend/styles")
21
+ assert response.status_code == 200
22
+ data = response.json()
23
+ assert "styles" in data
24
+ assert len(data["styles"]) > 0
25
+
26
+
27
  def test_commend_generate_rejects_invalid_url(client: TestClient) -> None:
28
  """Generate endpoint should reject a non-YouTube URL."""
29
  response = client.post(
 
34
  "style": "supportive",
35
  },
36
  )
37
+ assert response.status_code in (400, 401, 422)
38
+
39
+
40
+ def test_commend_generate_rejects_empty_url(client: TestClient) -> None:
41
+ """Generate endpoint should reject empty URL."""
42
+ response = client.post(
43
+ "/api/commend/generate",
44
+ json={
45
+ "url": "",
46
+ "language": "en",
47
+ "style": "supportive",
48
+ },
49
+ )
50
+ assert response.status_code in (400, 401, 422)
51
+
52
+
53
+ def test_commend_post_disabled_by_default(client: TestClient) -> None:
54
+ """Post endpoint should be disabled by default (feature flag)."""
55
+ response = client.post(
56
+ "/api/commend/post",
57
+ json={
58
+ "videoId": "dQw4w9WgXcQ",
59
+ "comment": "Test comment",
60
+ },
61
+ )
62
+ # Either 401 (auth) or 403 (feature flag disabled)
63
+ assert response.status_code in (401, 403, 422)
tests/test_data_processing.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for /api/process/audio endpoint."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import io
6
+
7
+ from fastapi.testclient import TestClient
8
+
9
+
10
+ def test_audio_rejects_non_audio(client: TestClient) -> None:
11
+ """Should reject non-audio content type."""
12
+ fake = io.BytesIO(b"not audio")
13
+ response = client.post(
14
+ "/api/process/audio",
15
+ data={"options": '{"pitch_shift": 0}'},
16
+ files={"file": ("test.txt", fake, "text/plain")},
17
+ )
18
+ assert response.status_code == 400
19
+ assert "audio" in response.json()["detail"].lower()
20
+
21
+
22
+ def test_audio_rejects_missing_content_type(client: TestClient) -> None:
23
+ """Should reject file with no content type."""
24
+ fake = io.BytesIO(b"some bytes")
25
+ response = client.post(
26
+ "/api/process/audio",
27
+ data={"options": '{"pitch_shift": 0}'},
28
+ files={"file": ("test.bin", fake, "")},
29
+ )
30
+ # Empty content_type should be treated as invalid
31
+ assert response.status_code == 400
32
+
33
+
34
+ def test_audio_rejects_missing_file(client: TestClient) -> None:
35
+ """Should reject request without file."""
36
+ response = client.post(
37
+ "/api/process/audio",
38
+ data={"options": '{"pitch_shift": 0}'},
39
+ )
40
+ assert response.status_code == 422