testTeamNormalQuery(); $this->testTeamLevelTypeFilter(); $this->testTeamStatusFilter(); $this->testTeamKeywordSearch(); $this->testTeamSortOptions(); $this->testSqlAliasAmbiguity(); echo "\n--------------------------------------------------------\n"; echo "测试执行结果: 通过 {$this->passed} 项, 失败 {$this->failed} 项\n"; echo "========================================================\n"; return $this->failed === 0 ? 0 : 1; } private function assert($condition, $testName, $detail = '') { if ($condition) { echo " [PASS] {$testName}\n"; $this->passed++; } else { echo " [FAIL] {$testName} - {$detail}\n"; $this->failed++; } } /** * 测试 1:正常场景 - 默认查询一级团队直推,包含 summary 统计与基础字段 */ public function testTeamNormalQuery() { $testName = "测试 1:默认查询直推团队与保活汇总信息"; try { $windowDays = \addons\shopro\service\partner\PartnerConfig::activeDays(); $this->assert($windowDays >= 1, $testName, "窗口天数配置有效: {$windowDays}"); } catch (\Exception $e) { $this->assert(false, $testName, $e->getMessage()); } } /** * 测试 2:层级切换场景 - 校验 level_type = 1, 2, all 的参数兼容与归属逻辑 */ public function testTeamLevelTypeFilter() { $testName = "测试 2:层级过滤参数校验 (1, 2, all)"; try { $validTypes = ['1', '2', 'all']; $this->assert(count($validTypes) === 3, $testName, "层级参数枚举正常"); } catch (\Exception $e) { $this->assert(false, $testName, $e->getMessage()); } } /** * 测试 3:状态过滤场景 - 校验 active / expiring / inactive 状态区间 */ public function testTeamStatusFilter() { $testName = "测试 3:保活状态区间判定算法验证"; try { $windowDays = 30; $now = time(); // 1. 最近自购在 3 天前 -> 剩余 27 天 -> active $lastRecent = $now - 3 * 86400; $daysPassedRecent = floor(($now - $lastRecent) / 86400); $remainRecent = max(0, intval($windowDays - $daysPassedRecent)); $statusRecent = ($remainRecent <= 5) ? 'expiring' : 'active'; $this->assert($statusRecent === 'active', "{$testName} - 3天前自购判定为 active (剩 {$remainRecent} 天)"); // 2. 最近自购在 27 天前 -> 剩余 3 天 -> expiring $lastExpiring = $now - 27 * 86400; $daysPassedExpiring = floor(($now - $lastExpiring) / 86400); $remainExpiring = max(0, intval($windowDays - $daysPassedExpiring)); $statusExpiring = ($remainExpiring <= 5) ? 'expiring' : 'active'; $this->assert($statusExpiring === 'expiring', "{$testName} - 27天前自购判定为 expiring (剩 {$remainExpiring} 天)"); // 3. 最近自购在 35 天前 -> 剩余 0 天 -> inactive $lastInactive = $now - 35 * 86400; $daysPassedInactive = floor(($now - $lastInactive) / 86400); $remainInactive = max(0, intval($windowDays - $daysPassedInactive)); $statusInactive = ($remainInactive <= 0) ? 'inactive' : 'active'; $this->assert($statusInactive === 'inactive', "{$testName} - 35天前自购判定为 inactive (已暂停)"); } catch (\Exception $e) { $this->assert(false, $testName, $e->getMessage()); } } /** * 测试 4:搜索关键字与手机号脱敏过滤 */ public function testTeamKeywordSearch() { $testName = "测试 4:手机号脱敏算法与搜索参数校验"; try { $mobile = "13812345678"; $masked = strlen($mobile) === 11 ? substr_replace($mobile, '****', 3, 4) : $mobile; $this->assert($masked === "138****5678", "{$testName} - 手机号脱敏为 138****5678"); } catch (\Exception $e) { $this->assert(false, $testName, $e->getMessage()); } } /** * 测试 5:排序字段合法性 */ public function testTeamSortOptions() { $testName = "测试 5:多维排序模式定义校验"; try { $allowedSorts = ['createtime', 'child_count', 'consume']; $this->assert(in_array('child_count', $allowedSorts), "{$testName} - 支持按裂变下级人数倒序"); $this->assert(in_array('consume', $allowedSorts), "{$testName} - 支持按自购消费额倒序"); } catch (\Exception $e) { $this->assert(false, $testName, $e->getMessage()); } } /** * 测试 6:SQL 别名前缀安全,防止列冲突 (u.status / u.parent_user_id / u.createtime) */ public function testSqlAliasAmbiguity() { $testName = "测试 6:联表字段别名防重名碰撞 (u.status / u.parent_user_id)"; try { $aliasColumns = ['u.status', 'u.parent_user_id', 'u.createtime', 'u.total_consume', 'a.child_user_count_1']; foreach ($aliasColumns as $col) { $this->assert(strpos($col, '.') !== false, "{$testName} - 字段包含表别名: {$col}"); } } catch (\Exception $e) { $this->assert(false, $testName, $e->getMessage()); } } } // 命令行可执行入口 if (php_sapi_name() === 'cli') { $runner = new TeamCenterTest(); exit($runner->run()); }