blob: 98d5687ddfc771c9cd8dda21d312de82a7d22ffa [file] [log] [blame]
import 'package:devtools_app/src/charts/chart.dart';
import 'package:devtools_app/src/charts/chart_controller.dart';
import 'package:devtools_app/src/charts/chart_trace.dart';
import 'package:devtools_app/src/globals.dart';
import 'package:devtools_app/src/memory/memory_charts.dart';
import 'package:devtools_app/src/service_manager.dart';
import 'package:devtools_app/src/utils.dart';
import 'package:devtools_shared/devtools_shared.dart';
import 'package:devtools_testing/support/memory_test_data.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'support/mocks.dart';
import 'support/wrappers.dart';
void main() {
const windowSize = Size(2225.0, 1000.0);
setUp(() {
setGlobal(ServiceConnectionManager, FakeServiceManager());
});
group(
'Chart Timeseries',
() {
MemoryJson memoryJson;
void loadData() {
// Load canned data testHeapSampleData.
memoryJson ??=
SamplesMemoryJson.decode(argJsonString: testHeapSampleData);
expect(memoryJson.data.length, equals(104));
}
///////////////////////////////////////////////////////////////////////////
// Scaled Y-axis chart. //
///////////////////////////////////////////////////////////////////////////
// Used for test.
final _rawExternal = <Data>[];
final _rawUsed = <Data>[];
final _rawCapacity = <Data>[];
final _rawRSS = <Data>[];
int externalTraceIndex;
int usedTraceIndex;
int capacityTraceIndex;
int rssTraceIndex;
void setupTraces(ChartController controller) {
// External Heap
externalTraceIndex = controller.createTrace(
ChartType.line,
PaintCharacteristics(
color: Colors.lightGreen,
symbol: ChartSymbol.disc,
diameter: 1.5,
),
name: externalDisplay,
);
// Used Heap
usedTraceIndex = controller.createTrace(
ChartType.line,
PaintCharacteristics(
color: Colors.blue[200],
symbol: ChartSymbol.disc,
diameter: 1.5,
),
name: usedDisplay,
);
// Heap Capacity
capacityTraceIndex = controller.createTrace(
ChartType.line,
PaintCharacteristics(
color: Colors.grey[400],
diameter: 0.0,
symbol: ChartSymbol.dashedLine,
),
name: allocatedDisplay,
);
// RSS
rssTraceIndex = controller.createTrace(
ChartType.line,
PaintCharacteristics(
color: Colors.yellow,
symbol: ChartSymbol.dashedLine,
strokeWidth: 2,
),
name: rssDisplay,
);
expect(controller.traces.length, equals(4));
for (var index = 0; index < controller.traces.length; index++) {
switch (index) {
case 0:
expect(externalTraceIndex, equals(0));
expect(controller.traces[index].name, externalDisplay);
break;
case 1:
expect(usedTraceIndex, equals(1));
expect(controller.traces[index].name, usedDisplay);
break;
case 2:
expect(capacityTraceIndex, equals(2));
expect(controller.traces[index].name, allocatedDisplay);
break;
case 3:
expect(rssTraceIndex, equals(3));
expect(controller.traces[index].name, rssDisplay);
break;
}
}
}
void addDataToTrace(
ChartController controller,
int traceIndex,
Data data,
) {
controller.trace(traceIndex).addDatum(data);
}
Future<void> pumpChart(WidgetTester tester, Key theKey, Chart theChart,
double chartHeight) async {
await tester.pumpWidget(wrap(LayoutBuilder(
key: theKey,
builder: (context, constraints) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: chartHeight,
child: Padding(
padding: const EdgeInsets.all(0.0),
child: theChart,
),
),
],
);
})));
await tester.pumpAndSettle();
}
void chartAllData(ChartController controller) {
for (var datumIndex = 0;
datumIndex < memoryJson.data.length;
datumIndex++) {
final datum = memoryJson.data[datumIndex];
final external = datum.external.toDouble();
final used = datum.used.toDouble();
final capacity = datum.capacity.toDouble();
final rss = datum.rss.toDouble();
controller.addTimestamp(datum.timestamp);
_rawExternal.add(Data(datum.timestamp, external));
addDataToTrace(controller, externalTraceIndex, _rawExternal.last);
_rawUsed.add(Data(datum.timestamp, external + used));
addDataToTrace(controller, usedTraceIndex, _rawUsed.last);
_rawCapacity.add(Data(datum.timestamp, capacity));
addDataToTrace(controller, capacityTraceIndex, _rawCapacity.last);
_rawRSS.add(Data(datum.timestamp, rss));
addDataToTrace(controller, rssTraceIndex, _rawRSS.last);
}
}
Future<void> setupScaledChart(
WidgetTester tester, ChartController controller, Key chartKey) async {
final theChart = Chart(controller, title: 'Scaled Chart');
setupTraces(controller);
loadData();
await pumpChart(tester, chartKey, theChart, 250);
expect(find.byWidget(theChart), findsOneWidget);
// Validate the X axis before data added.
expect(controller.visibleTicks, equals(215));
expect(controller.xCanvasChart, equals(50.0));
expect(controller.xPaddingRight, equals(0.0));
expect(controller.displayXLabels, true);
expect(controller.canvasChartWidth, equals(2150.0));
// Validate the Y axis before data added.
expect(controller.yScale.computedMin, equals(0.0));
expect(controller.yScale.computedMax, equals(0.0));
expect(controller.yScale.labelTicks, equals(0.0));
expect(controller.yScale.labelUnitExponent, 0.0);
expect(controller.yScale.tickSpacing, equals(1.0));
expect(controller.yScale.maxPoint, equals(0.0));
expect(controller.yScale.maxTicks, equals(185.0));
chartAllData(controller);
}
/// Validate the labels displayed on the y-axis.
void validateScaledYLabels(ChartController controller) {
// Validate the labels displayed on the y-axis.
final yScale = controller.yScale;
expect(yScale.labelTicks, equals(10));
for (var labelIndex = yScale.labelTicks;
labelIndex >= 0;
labelIndex--) {
final labelName = ChartPainter.constructLabel(
labelIndex.toInt(),
yScale.labelUnitExponent.toInt(),
);
// Ensure Y axis labels match.
final expectedLabels = [
'0',
'100M',
'200M',
'300M',
'400M',
'500M',
'600M',
'700M',
'800M',
'900M',
'1000M',
];
expect(labelName, expectedLabels[labelIndex.toInt()]);
}
}
testWidgetsWithWindowSize(
'Scaled Y-axis live',
windowSize,
(WidgetTester tester) async {
const chartKey = Key('Chart');
final controller = ChartController();
await setupScaledChart(tester, controller, chartKey);
// Check live view zoom.
controller.zoomDuration = const Duration();
await tester.pumpAndSettle(const Duration(seconds: 2));
await expectLater(
find.byKey(chartKey),
matchesGoldenFile('goldens/memory_chart_scaled_live.png'),
);
// Await delay for golden comparison.
await tester.pumpAndSettle(const Duration(seconds: 2));
// Validate the X axis after data added to all traces.
expect(controller.visibleTicks, equals(215));
expect(controller.xCanvasChart, equals(50.0));
expect(controller.xPaddingRight, equals(0.0));
expect(controller.displayXLabels, true);
expect(controller.canvasChartWidth, equals(2150.0));
// Validate the Y axis after data added to all traces.
expect(controller.yScale.computedMin, equals(0.0));
expect(controller.yScale.computedMax, equals(719576719.5767195));
expect(controller.yScale.labelTicks, equals(10.0));
expect(controller.yScale.labelUnitExponent, 8.0);
expect(controller.yScale.tickSpacing, equals(5291005.291005291));
expect(controller.yScale.maxPoint, equals(717799424.0));
expect(controller.yScale.maxTicks, equals(190.0));
final externalTrace = controller.trace(externalTraceIndex);
expect(externalTrace.dataYMax, equals(357446512.0));
expect(externalTrace.data.length, equals(_rawExternal.length));
final usedTrace = controller.trace(usedTraceIndex);
expect(usedTrace.dataYMax, equals(409913568.0));
expect(usedTrace.data.length, equals(_rawUsed.length));
final capacityTrace = controller.trace(capacityTraceIndex);
expect(capacityTrace.dataYMax, equals(422794096.0));
expect(capacityTrace.data.length, equals(_rawCapacity.length));
final rssTrace = controller.trace(rssTraceIndex);
expect(rssTrace.dataYMax, equals(717799424.0));
expect(rssTrace.data.length, equals(_rawRSS.length));
expect(controller.timestampsLength, equals(104));
validateScaledYLabels(controller);
// Validate the x-axis labels.
expect(controller.labelTimestamps.length, equals(2));
expect(controller.labelTimestamps[0], equals(1611247510202));
expect(controller.labelTimestamps[1], equals(1611247530281));
// Validate using UTC timezone.
expect(
prettyTimestamp(controller.labelTimestamps[0], isUtc: true),
equals('16:45:10'),
);
expect(
prettyTimestamp(controller.labelTimestamps[1], isUtc: true),
equals('16:45:30'),
);
},
);
void checkScaledXAxis2Labels(ChartController controller) {
// Validate the x-axis labels.
expect(controller.labelTimestamps.length, equals(1));
expect(controller.labelTimestamps[0], equals(1611247510202));
// Validate using UTC timezone.
expect(
prettyTimestamp(controller.labelTimestamps[0], isUtc: true),
equals('16:45:10'),
);
}
testWidgetsWithWindowSize('Scaled Y-axis all', windowSize,
(WidgetTester tester) async {
const chartKey = Key('Chart');
final controller = ChartController();
await setupScaledChart(tester, controller, chartKey);
// Check A=all data view zoom.
controller.zoomDuration = null;
await tester.pumpAndSettle(const Duration(seconds: 2));
await expectLater(
find.byKey(chartKey),
matchesGoldenFile('goldens/memory_chart_scaled_all.png'),
);
// Await delay for golden comparison.
await tester.pumpAndSettle(const Duration(seconds: 2));
// Validate the X axis after data added to all traces.
expect(controller.visibleTicks, equals(104));
expect(controller.xCanvasChart, equals(50.0));
expect(controller.xPaddingRight, equals(0.0));
expect(controller.displayXLabels, true);
expect(controller.canvasChartWidth, equals(2150.0));
// Validate the Y axis after data added to all traces.
expect(controller.yScale.computedMin, equals(0.0));
expect(controller.yScale.computedMax, equals(719576719.5767195));
expect(controller.yScale.labelTicks, equals(10.0));
expect(controller.yScale.labelUnitExponent, 8.0);
expect(controller.yScale.tickSpacing, equals(5291005.291005291));
expect(controller.yScale.maxPoint, equals(717799424.0));
expect(controller.yScale.maxTicks, equals(190.0));
validateScaledYLabels(controller);
checkScaledXAxis2Labels(controller);
});
testWidgetsWithWindowSize('Scaled Y-axis Five Minutes', windowSize,
(WidgetTester tester) async {
const chartKey = Key('Chart');
final controller = ChartController();
await setupScaledChart(tester, controller, chartKey);
// Check 5 minute data view zoom.
controller.zoomDuration = const Duration(minutes: 5);
await tester.pumpAndSettle(const Duration(seconds: 2));
await expectLater(
find.byKey(chartKey),
matchesGoldenFile('goldens/memory_chart_scaled_five_minute.png'),
);
// Await delay for golden comparison.
await tester.pumpAndSettle(const Duration(seconds: 2));
// Validate the X axis after data added to all traces.
expect(controller.visibleTicks, equals(1704));
expect(controller.xCanvasChart, equals(50.0));
expect(controller.xPaddingRight, equals(0.6880000000001019));
expect(controller.displayXLabels, true);
expect(controller.canvasChartWidth, equals(2149.312));
// Validate the Y axis after data added to all traces.
expect(controller.yScale.computedMin, equals(0.0));
expect(controller.yScale.computedMax, equals(719576719.5767195));
expect(controller.yScale.labelTicks, equals(10.0));
expect(controller.yScale.labelUnitExponent, 8.0);
expect(controller.yScale.tickSpacing, equals(5291005.291005291));
expect(controller.yScale.maxPoint, equals(717799424.0));
expect(controller.yScale.maxTicks, equals(190.0));
validateScaledYLabels(controller);
checkScaledXAxis2Labels(controller);
});
///////////////////////////////////////////////////////////////////////////
// Fixed Y-axis chart. //
///////////////////////////////////////////////////////////////////////////
final _rawGcEvents = <Data>[];
final _rawSnapshotEvents = <Data>[];
final _rawAutoSnapshotEvents = <Data>[];
int snapshotTraceIndex;
int autoSnapshotTraceIndex;
int manualGCTraceIndex;
int monitorTraceIndex;
int monitorResetTraceIndex;
int gcTraceIndex;
void setupFixedTraces(ChartController controller) {
// Snapshot
snapshotTraceIndex = controller.createTrace(
ChartType.symbol,
PaintCharacteristics(
color: Colors.green,
strokeWidth: 4,
diameter: 6,
fixedMinY: 0.4,
fixedMaxY: 2.4,
),
name: 'Snapshot',
);
// Auto-snapshot
autoSnapshotTraceIndex = controller.createTrace(
ChartType.symbol,
PaintCharacteristics(
color: Colors.red,
strokeWidth: 4,
diameter: 6,
fixedMinY: 0.4,
fixedMaxY: 2.4,
),
name: 'Auto-Snapshot',
);
// Manual GC
manualGCTraceIndex = controller.createTrace(
ChartType.symbol,
PaintCharacteristics(
color: Colors.blue,
strokeWidth: 4,
diameter: 6,
fixedMinY: 0.4,
fixedMaxY: 2.4,
),
name: 'Manual GC',
);
// Monitor
monitorTraceIndex = controller.createTrace(
ChartType.symbol,
PaintCharacteristics(
color: Colors.yellow,
strokeWidth: 4,
diameter: 6,
fixedMinY: 0.4,
fixedMaxY: 2.4,
),
name: 'Monitor',
);
monitorResetTraceIndex = controller.createTrace(
ChartType.symbol,
PaintCharacteristics.concentric(
color: Colors.grey[600],
strokeWidth: 4,
diameter: 6,
fixedMinY: 0.4,
fixedMaxY: 2.4,
concentricCenterColor: Colors.yellowAccent,
concentricCenterDiameter: 4,
),
name: 'Monitor Reset',
);
// VM GC
gcTraceIndex = controller.createTrace(
ChartType.symbol,
PaintCharacteristics(
color: Colors.blue,
symbol: ChartSymbol.disc,
diameter: 4,
fixedMinY: 0.4,
fixedMaxY: 2.4,
),
name: 'VM GC',
);
}
/// Event to display in the event pane (User initiated GC, snapshot,
/// automatic snapshot, etc.)
const visibleEvent = 2.4;
/// Monitor events Y axis.
const visibleMonitorEvent = 1.4;
/// VM's GCs are displayed in a smaller glyph and closer to the heap graph.
const visibleVmEvent = 0.4;
// Load all data into the chart's traces.
void chartAllFixedData(ChartController controller) {
for (var datumIndex = 0;
datumIndex < memoryJson.data.length;
datumIndex++) {
final datum = memoryJson.data[datumIndex];
controller.addTimestamp(datum.timestamp);
final event = datum.memoryEventInfo;
if (datum.isGC) {
// VM GC
_rawGcEvents.add(Data(datum.timestamp, visibleVmEvent));
addDataToTrace(controller, gcTraceIndex, _rawGcEvents.last);
} else if (event.isEventGC) {
// Manual GC
final rawData = Data(datum.timestamp, visibleVmEvent);
addDataToTrace(controller, manualGCTraceIndex, rawData);
} else if (event.isEventSnapshot) {
_rawSnapshotEvents.add(Data(datum.timestamp, visibleEvent));
addDataToTrace(
controller,
snapshotTraceIndex,
_rawSnapshotEvents.last,
);
} else if (event.isEventSnapshotAuto) {
_rawAutoSnapshotEvents.add(Data(datum.timestamp, visibleEvent));
addDataToTrace(
controller,
autoSnapshotTraceIndex,
_rawAutoSnapshotEvents.last,
);
} else if (event.isEventAllocationAccumulator) {
final monitorType = event.allocationAccumulator;
final rawData = Data(datum.timestamp, visibleMonitorEvent);
if (monitorType.isEmpty) continue;
if (monitorType.isStart) {
addDataToTrace(controller, monitorTraceIndex, rawData);
} else if (monitorType.isReset) {
addDataToTrace(controller, monitorResetTraceIndex, rawData);
} else {
assert(false, 'Unknown monitor type');
}
} else if (event.isEmpty) {
assert(false, 'Unexpected EventSample of isEmpty.');
}
}
}
Future<void> setupFixedChart(
WidgetTester tester, ChartController controller, Key chartKey) async {
controller.setFixedYRange(0.4, 2.4);
final theChart = Chart(controller, title: 'Fixed Chart');
await pumpChart(tester, chartKey, theChart, 150);
expect(find.byWidget(theChart), findsOneWidget);
setupFixedTraces(controller);
loadData();
// Validate the X axis before any data.
expect(controller.visibleTicks, equals(215));
expect(controller.xCanvasChart, equals(50.0));
expect(controller.xPaddingRight, equals(0.0));
expect(controller.displayXLabels, true);
expect(controller.canvasChartWidth, equals(2150.0));
// Validate the Y axis before any data.
expect(controller.yScale.computedMin, equals(0.3707865168539326));
expect(controller.yScale.computedMax, equals(2.426966292134831));
expect(controller.yScale.labelTicks, equals(3.0));
expect(controller.yScale.labelUnitExponent, 0.0);
expect(controller.yScale.tickSpacing, equals(0.033707865168539325));
expect(controller.yScale.maxPoint, equals(2.4));
expect(controller.yScale.maxTicks, equals(90.0));
// Load all data in the chart.
chartAllFixedData(controller);
}
testWidgetsWithWindowSize(
'Fixed Y-axis',
windowSize,
(WidgetTester tester) async {
const chartKey = Key('Chart');
final controller = ChartController();
await setupFixedChart(tester, controller, chartKey);
// Check live view zoom.
controller.zoomDuration = const Duration();
await tester.pumpAndSettle(const Duration(seconds: 2));
await expectLater(
find.byKey(chartKey),
matchesGoldenFile('goldens/memory_chart_fixed_live.png'),
);
// Await delay for golden comparison.
await tester.pumpAndSettle(const Duration(seconds: 2));
// Validate the X axis after data added to all traces.
expect(controller.visibleTicks, equals(215));
expect(controller.xCanvasChart, equals(50.0));
expect(controller.xPaddingRight, equals(0.0));
expect(controller.displayXLabels, true);
expect(controller.canvasChartWidth, equals(2150.0));
// Validate the Y axis after data added to all traces.
expect(controller.yScale.computedMin, equals(0.0));
// Rest of data is out of view because we're live view max is now 1.4
// and only 2 labels visible.
expect(controller.yScale.computedMax, equals(2.426966292134831));
expect(controller.yScale.labelTicks, equals(3.0));
expect(controller.yScale.labelUnitExponent, 0.0);
expect(controller.yScale.tickSpacing, equals(0.033707865168539325));
// Max live view max is 1.4 other data is not in the visible view.
expect(controller.yScale.maxPoint, equals(2.4));
expect(controller.yScale.maxTicks, equals(90.0));
final snapshotTrace = controller.trace(snapshotTraceIndex);
expect(snapshotTrace.dataYMax, equals(0.0));
expect(snapshotTrace.data.length, equals(1));
final autoSnapshotTrace = controller.trace(autoSnapshotTraceIndex);
expect(autoSnapshotTrace.dataYMax, equals(0.0));
expect(autoSnapshotTrace.data.length, equals(0));
final manualGCTrace = controller.trace(manualGCTraceIndex);
expect(manualGCTrace.dataYMax, equals(0.0));
expect(manualGCTrace.data.length, equals(0));
final monitorTrace = controller.trace(monitorTraceIndex);
expect(monitorTrace.dataYMax, equals(0.0));
expect(monitorTrace.data.length, equals(2));
final monitorResetTrace = controller.trace(monitorResetTraceIndex);
expect(monitorResetTrace.dataYMax, equals(0.0));
expect(monitorResetTrace.data.length, equals(1));
final gcTrace = controller.trace(gcTraceIndex);
expect(gcTrace.dataYMax, equals(0.0));
expect(gcTrace.data.length, equals(46));
expect(controller.timestampsLength, equals(104));
// Validate the labels displayed on the y-axis.
final yScale = controller.yScale;
expect(yScale.labelTicks, equals(3.0));
for (var labelIndex = yScale.labelTicks;
labelIndex >= 0;
labelIndex--) {
final labelName = ChartPainter.constructLabel(
labelIndex.toInt(),
yScale.labelUnitExponent.toInt(),
);
final expectedLabels = ['0', '1', '2', '3'];
expect(labelName, expectedLabels[labelIndex.toInt()]);
}
// Validate the x-axis labels.
expect(controller.labelTimestamps.length, equals(2));
expect(controller.labelTimestamps[0], equals(1611247510202));
expect(controller.labelTimestamps[1], equals(1611247530281));
// Validate using UTC timezone.
expect(
prettyTimestamp(controller.labelTimestamps[0], isUtc: true),
equals('16:45:10'),
);
expect(
prettyTimestamp(controller.labelTimestamps[1], isUtc: true),
equals('16:45:30'),
);
},
);
void checkFixedXAxis2Labels(ChartController controller) {
// Validate the x-axis labels.
expect(controller.labelTimestamps.length, equals(1));
expect(controller.labelTimestamps[0], equals(1611247510202));
// Validate using UTC timezone.
expect(
prettyTimestamp(controller.labelTimestamps[0], isUtc: true),
equals('16:45:10'),
);
}
testWidgetsWithWindowSize('Fixed Y-axis all', windowSize,
(WidgetTester tester) async {
const chartKey = Key('Chart');
final controller = ChartController();
await setupFixedChart(tester, controller, chartKey);
// Check all data view zoom.
controller.zoomDuration = null;
await tester.pumpAndSettle(const Duration(seconds: 15));
await expectLater(
find.byKey(chartKey),
matchesGoldenFile('goldens/memory_chart_fixed_all.png'),
);
// Await delay for golden comparison.
await tester.pumpAndSettle(const Duration(seconds: 2));
// Validate the X axis after data added to all traces.
expect(controller.visibleTicks, equals(104));
expect(controller.xCanvasChart, equals(50.0));
expect(controller.xPaddingRight, equals(0.0));
expect(controller.displayXLabels, true);
expect(controller.canvasChartWidth, equals(2150.0));
// Validate the Y axis after data added to all traces.
expect(controller.yScale.computedMin, equals(0.0));
expect(controller.yScale.computedMax, equals(2.426966292134831));
expect(controller.yScale.labelTicks, equals(3.0));
expect(controller.yScale.labelUnitExponent, 0.0);
expect(controller.yScale.tickSpacing, equals(0.033707865168539325));
expect(controller.yScale.maxPoint, equals(2.4));
expect(controller.yScale.maxTicks, equals(90.0));
// Validate the labels displayed on the y-axis.
final yScale = controller.yScale;
expect(yScale.labelTicks, equals(3));
for (var labelIndex = yScale.labelTicks;
labelIndex >= 0;
labelIndex--) {
final labelName = ChartPainter.constructLabel(
labelIndex.toInt(),
yScale.labelUnitExponent.toInt(),
);
final expectedLabels = ['0', '1', '2', '3'];
expect(labelName, expectedLabels[labelIndex.toInt()]);
}
checkFixedXAxis2Labels(controller);
});
testWidgetsWithWindowSize('Fixed Y-axis 5 Minutes', windowSize,
(WidgetTester tester) async {
const chartKey = Key('Chart');
final controller = ChartController();
await setupFixedChart(tester, controller, chartKey);
// Check all data view zoom.
controller.zoomDuration = const Duration(minutes: 5);
await tester.pumpAndSettle(const Duration(seconds: 15));
await expectLater(
find.byKey(chartKey),
matchesGoldenFile('goldens/memory_chart_fixed_five_minutes.png'),
);
// Await delay for golden comparison.
await tester.pumpAndSettle(const Duration(seconds: 2));
// Validate the X axis after data added to all traces.
expect(controller.visibleTicks, equals(1704));
expect(controller.xCanvasChart, equals(50.0));
expect(controller.xPaddingRight, equals(0.6880000000001019));
expect(controller.displayXLabels, true);
expect(controller.canvasChartWidth, equals(2149.312));
// Validate the Y axis after data added to all traces.
expect(controller.yScale.computedMin, equals(0.0));
expect(controller.yScale.computedMax, equals(2.426966292134831));
expect(controller.yScale.labelTicks, equals(3.0));
expect(controller.yScale.labelUnitExponent, 0.0);
expect(controller.yScale.tickSpacing, equals(0.033707865168539325));
expect(controller.yScale.maxPoint, equals(2.4));
expect(controller.yScale.maxTicks, equals(90.0));
// Validate the labels displayed on the y-axis.
final yScale = controller.yScale;
expect(yScale.labelTicks, equals(3));
for (var labelIndex = yScale.labelTicks;
labelIndex >= 0;
labelIndex--) {
final labelName = ChartPainter.constructLabel(
labelIndex.toInt(),
yScale.labelUnitExponent.toInt(),
);
final expectedLabels = ['0', '1', '2', '3'];
expect(labelName, expectedLabels[labelIndex.toInt()]);
}
checkFixedXAxis2Labels(controller);
});
},
);
}