100, 'Feb' => 150, 'Mar' => 120, ]; $chart = BarChart::fromArray($data); expect($chart->data->count())->toBe(3); }); test('can render bar chart to SVG', function () { $data = [ 'Jan' => 100, 'Feb' => 150, 'Mar' => 120, ]; $chart = BarChart::fromArray($data); $svg = $chart->render(); expect($svg)->toContain('and($svg)->toContain('and($svg)->toContain('Jan') ->and($svg)->toContain('Feb') ->and($svg)->toContain('Mar'); }); test('chart data validates minimum value correctly', function () { $data = new ChartData([ new DataPoint('A', 10), new DataPoint('B', 5), new DataPoint('C', 15), ]); expect($data->getMinValue())->toBe(5.0); }); test('chart data validates maximum value correctly', function () { $data = new ChartData([ new DataPoint('A', 10), new DataPoint('B', 5), new DataPoint('C', 15), ]); expect($data->getMaxValue())->toBe(15.0); }); test('chart data calculates sum correctly', function () { $data = new ChartData([ new DataPoint('A', 10), new DataPoint('B', 20), new DataPoint('C', 30), ]); expect($data->getSum())->toBe(60.0); }); test('chart data calculates average correctly', function () { $data = new ChartData([ new DataPoint('A', 10), new DataPoint('B', 20), new DataPoint('C', 30), ]); expect($data->getAverage())->toBe(20.0); }); test('chart config can create dark theme', function () { $config = ChartConfig::default(); $darkConfig = $config->darkTheme(); expect($darkConfig->backgroundColor->toHex())->toContain('11'); // Dark background }); test('chart data cannot be empty', function () { new ChartData([]); })->throws(\App\Framework\Exception\FrameworkException::class); test('data point can check if positive', function () { $positive = new DataPoint('A', 10); $negative = new DataPoint('B', -5); $zero = new DataPoint('C', 0); expect($positive->isPositive())->toBeTrue() ->and($negative->isPositive())->toBeFalse() ->and($zero->isPositive())->toBeFalse(); }); test('data point can scale value', function () { $point = new DataPoint('A', 10); $scaled = $point->scale(2.5); expect($scaled->value)->toBe(25.0) ->and($scaled->label)->toBe('A'); });