assertNotNull($sheet, $code); $parsed = TrackScoringSheet::parseAndValidateConfig($sheet); $this->assertTrue($parsed['ok'], $code.': '.($parsed['message'] ?? '')); $this->assertSame(100.0, $parsed['sheet']['full_score']); } } public function test_default_ai_track_sheet_sums_to_100(): void { $sheet = DefaultTrackScoringSheets::forTrackCode('xiaofei_ai', '消费+人工智能'); $this->assertNotNull($sheet); $parsed = TrackScoringSheet::parseAndValidateConfig($sheet); $this->assertTrue($parsed['ok']); $this->assertSame(100.0, $parsed['sheet']['full_score']); $this->assertCount(8, $parsed['sheet']['items']); } public function test_config_rejects_sum_not_100(): void { $parsed = TrackScoringSheet::parseAndValidateConfig([ 'version' => 1, 'title' => 't', 'items' => [ [ 'key' => 'a', 'sort' => 1, 'category' => '通用指标', 'title' => 'A', 'criteria' => '', 'max_score' => 40, ], ], ]); $this->assertFalse($parsed['ok']); $this->assertStringContainsString('100', $parsed['message']); } public function test_submit_accepts_total_including_zero(): void { $sheet = DefaultTrackScoringSheets::forTrackCode('xiaofei_ai', '消费+人工智能'); $this->assertNotNull($sheet); $parsed = TrackScoringSheet::parseAndValidateConfig($sheet); $this->assertTrue($parsed['ok']); $ok = TrackScoringSheet::normalizeSubmitPayload($parsed['sheet'], ['line_total' => 0]); $this->assertTrue($ok['ok']); $this->assertSame(0.0, $ok['line_total']); $ok100 = TrackScoringSheet::normalizeSubmitPayload($parsed['sheet'], ['line_total' => 100]); $this->assertTrue($ok100['ok']); $this->assertSame(100.0, $ok100['line_total']); $ok2dp = TrackScoringSheet::normalizeSubmitPayload($parsed['sheet'], ['line_total' => '88.50']); $this->assertTrue($ok2dp['ok']); $this->assertSame(88.5, $ok2dp['line_total']); $missing = TrackScoringSheet::normalizeSubmitPayload($parsed['sheet'], []); $this->assertFalse($missing['ok']); $this->assertStringContainsString('请填写', $missing['message']); } public function test_submit_rejects_out_of_range_total(): void { $sheet = DefaultTrackScoringSheets::forTrackCode('xiaofei_ai', '消费+人工智能'); $parsed = TrackScoringSheet::parseAndValidateConfig($sheet); $this->assertTrue($parsed['ok']); $over = TrackScoringSheet::normalizeSubmitPayload($parsed['sheet'], ['line_total' => 100.01]); $this->assertFalse($over['ok']); $this->assertStringContainsString('不能大于 100', $over['message']); $neg = TrackScoringSheet::normalizeSubmitPayload($parsed['sheet'], ['line_total' => -1]); $this->assertFalse($neg['ok']); $this->assertStringContainsString('不能为负数', $neg['message']); $tooManyDecimals = TrackScoringSheet::normalizeSubmitPayload($parsed['sheet'], ['line_total' => '88.501']); $this->assertFalse($tooManyDecimals['ok']); $this->assertStringContainsString('两位小数', $tooManyDecimals['message']); } }