$values */ private function cfg(array $values): ConfigService { $cfg = Mockery::mock(ConfigService::class)->makePartial(); $cfg->shouldReceive('get')->andReturnUsing(function (string $key, $default = null) use ($values) { return array_key_exists($key, $values) ? $values[$key] : $default; }); $cfg->shouldReceive('getString')->andReturnUsing(function (string $key, string $default = '') use ($values) { $value = $values[$key] ?? $default; return trim((string) $value); }); $cfg->shouldReceive('getBool')->andReturnUsing(function (string $key, bool $default = false) use ($values) { if (! array_key_exists($key, $values)) { return $default; } return filter_var($values[$key], FILTER_VALIDATE_BOOLEAN); }); return $cfg; } public function test_per_day_schedule_closes_before_global_end_day(): void { $weekly = json_encode([ 'mode' => 'per_day', 'days' => [ 'sat' => ['enabled' => true, 'start' => '08:30:00', 'end' => '21:30:00'], 'sun' => ['enabled' => true, 'start' => '08:30:00', 'end' => '21:30:00'], 'mon' => ['enabled' => true, 'start' => '08:30:00', 'end' => '21:00:00'], 'tue' => ['enabled' => true, 'start' => '08:30:00', 'end' => '21:30:00'], 'wed' => ['enabled' => true, 'start' => '08:30:00', 'end' => '21:30:00'], 'thu' => ['enabled' => true, 'start' => '08:30:00', 'end' => '21:30:00'], 'fri' => ['enabled' => true, 'start' => '08:30:00', 'end' => '21:30:00'], ], ], JSON_UNESCAPED_UNICODE); $cfg = $this->cfg([ 'close_price' => 'true', 'startDay' => '08:30', 'endDay' => '21:30', 'trading_hours_by_day' => $weekly, ]); $monday2115 = Carbon::create(2026, 8, 24, 21, 15, 0); $monday2059 = Carbon::create(2026, 8, 24, 20, 59, 0); $this->assertTrue($cfg->isOutsideTradingHours($monday2115)); $this->assertFalse($cfg->isOutsideTradingHours($monday2059)); } public function test_disabled_day_is_closed_all_day(): void { $weekly = json_encode([ 'mode' => 'per_day', 'days' => [ 'fri' => ['enabled' => false, 'start' => '08:30:00', 'end' => '21:30:00'], ], ], JSON_UNESCAPED_UNICODE); $cfg = $this->cfg([ 'close_price' => 'true', 'startDay' => '08:30', 'endDay' => '21:30', 'trading_hours_by_day' => $weekly, ]); $fridayNoon = Carbon::create(2026, 8, 28, 12, 0, 0); $this->assertTrue($cfg->isOutsideTradingHours($fridayNoon)); } public function test_apply_global_trading_hours_marks_closed_without_hiding_status_when_home_price_off(): void { $weekly = json_encode([ 'mode' => 'per_day', 'days' => [ 'mon' => ['enabled' => true, 'start' => '08:30:00', 'end' => '21:00:00'], ], ], JSON_UNESCAPED_UNICODE); $cfg = $this->cfg([ 'close_price' => 'true', 'show_home_price_when_closed' => 'false', 'show_last_price' => 'false', 'startDay' => '08:30', 'endDay' => '21:30', 'trading_hours_by_day' => $weekly, ]); $now = Carbon::create(2026, 8, 24, 21, 15, 0); Carbon::setTestNow($now); $result = $cfg->applyHomePriceDisplayState([ 'sell' => 100, 'buy' => 110, 'price' => 105, 'closed' => false, 'status' => 'open', ]); $this->assertTrue($result['closed']); $this->assertSame('closed', $result['status']); Carbon::setTestNow(); } public function test_outside_hours_shows_last_price_when_home_price_when_closed_is_on(): void { $cfg = $this->cfg([ 'close_price' => 'true', 'show_home_price_when_closed' => 'true', 'show_last_price' => 'false', 'startDay' => '11:00', 'endDay' => '20:30', ]); $now = Carbon::create(2026, 8, 25, 2, 3, 0); Carbon::setTestNow($now); $result = $cfg->applyHomePriceDisplayState([ 'sell' => 168000000, 'buy' => 168798112, 'price' => 168798112, 'closed' => false, 'status' => 'open', ]); $this->assertTrue($result['closed']); $this->assertSame('open', $result['status']); $this->assertSame(168798112, $result['buy']); Carbon::setTestNow(); } public function test_close_price_off_with_no_quote_is_no_quote(): void { $cfg = $this->cfg([ 'close_price' => 'false', 'show_last_price' => 'false', 'show_home_price_when_closed' => 'false', 'startDay' => '11:00', 'endDay' => '20:30', ]); $result = $cfg->applyHomePriceDisplayState([ 'sell' => 0, 'buy' => 0, 'price' => 0, 'closed' => false, ]); $this->assertFalse($result['closed']); $this->assertSame('no_quote', $result['status']); } public function test_inside_hours_with_quote_is_open(): void { $cfg = $this->cfg([ 'close_price' => 'true', 'show_last_price' => 'false', 'show_home_price_when_closed' => 'false', 'startDay' => '11:00', 'endDay' => '20:30', ]); $now = Carbon::create(2026, 8, 25, 12, 0, 0); Carbon::setTestNow($now); $result = $cfg->applyHomePriceDisplayState([ 'sell' => 100, 'buy' => 110, 'price' => 105, ]); $this->assertFalse($result['closed']); $this->assertSame('open', $result['status']); Carbon::setTestNow(); } public function test_trading_hours_setting_keys(): void { $cfg = new ConfigService(); $this->assertTrue($cfg->isTradingHoursSettingKey('close_price')); $this->assertTrue($cfg->isTradingHoursSettingKey('trading_hours_by_day')); $this->assertTrue($cfg->isTradingHoursSettingKey('show_home_price_when_closed')); $this->assertFalse($cfg->isTradingHoursSettingKey('name_fa')); } }