excel_plus 0.0.1 copy "excel_plus: ^0.0.1" to clipboard
excel_plus: ^0.0.1 copied to clipboard

A fast, memory-efficient Dart library for reading, creating, and editing Excel (.xlsx) files.

example/lib/main.dart

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

import 'tests/all_tests.dart';
import 'tests/test_case.dart';

void main() {
  runApp(const ExcelPlusTestApp());
}

class ExcelPlusTestApp extends StatelessWidget {
  const ExcelPlusTestApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'excel_plus Test',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
      ),
      home: const TestRunnerScreen(),
    );
  }
}

class TestRunnerScreen extends StatefulWidget {
  const TestRunnerScreen({super.key});

  @override
  State<TestRunnerScreen> createState() => TestRunnerScreenState();
}

class TestRunnerScreenState extends State<TestRunnerScreen> {
  late final List<TestCase> _tests;
  final Map<String, TestResult?> _results = {};
  bool _running = false;
  int _currentIndex = -1;
  int _passCount = 0;
  int _failCount = 0;
  int _totalDurationMs = 0;

  @override
  void initState() {
    super.initState();
    _tests = buildAllTests();
  }

  Future<void> runAll() async {
    setState(() {
      _running = true;
      _results.clear();
      _passCount = 0;
      _failCount = 0;
      _totalDurationMs = 0;
      _currentIndex = 0;
    });

    for (var i = 0; i < _tests.length; i++) {
      setState(() => _currentIndex = i);
      final result = await _tests[i].run();
      setState(() {
        _results[_tests[i].name] = result;
        if (result.passed) {
          _passCount++;
        } else {
          _failCount++;
        }
        _totalDurationMs += result.durationMs;
      });
    }

    setState(() {
      _running = false;
      _currentIndex = -1;
    });

    // Auto-save report after all tests complete
    await saveReport();
  }

  /// Generate a human-readable test report string.
  String generateReport() {
    final now = DateTime.now();
    final timestamp =
        '${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')} '
        '${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}:${now.second.toString().padLeft(2, '0')}';

    final buf = StringBuffer();
    buf.writeln('╔══════════════════════════════════════════════════════════════╗');
    buf.writeln('║              excel_plus — Integration Test Report           ║');
    buf.writeln('╠══════════════════════════════════════════════════════════════╣');
    buf.writeln('║  Date     : $timestamp');
    buf.writeln('║  Platform : ${Platform.operatingSystem} ${Platform.operatingSystemVersion}');
    buf.writeln('║  Dart     : ${Platform.version.split(' ').first}');
    buf.writeln('╚══════════════════════════════════════════════════════════════╝');
    buf.writeln();

    // Column widths
    const numW = 4;
    const statusW = 6;
    const nameW = 25;
    const timeW = 10;
    const memW = 10;

    // Header
    buf.writeln('${'#'.padRight(numW)} ${'STATUS'.padRight(statusW)} ${'TEST NAME'.padRight(nameW)} ${'TIME'.padLeft(timeW)} ${'MEMORY'.padLeft(memW)}   MESSAGE');
    buf.writeln('${'─' * numW} ${'─' * statusW} ${'─' * nameW} ${'─' * timeW} ${'─' * memW}   ${'─' * 30}');

    var idx = 1;
    for (final test in _tests) {
      final result = _results[test.name];
      final num = idx.toString().padRight(numW);
      final status = result == null
          ? 'SKIP'.padRight(statusW)
          : (result.passed ? 'PASS'.padRight(statusW) : 'FAIL'.padRight(statusW));
      final name = test.name.padRight(nameW);
      final time = result != null
          ? '${result.durationMs}ms'.padLeft(timeW)
          : '-'.padLeft(timeW);
      final mem = result?.peakMemoryKB != null
          ? '${result!.peakMemoryKB}KB'.padLeft(memW)
          : '-'.padLeft(memW);
      final msg = result?.message ?? '';

      buf.writeln('$num $status $name $time $mem   $msg');
      idx++;
    }

    buf.writeln();
    buf.writeln('─' * 80);

    // Summary
    final total = _tests.length;
    final ran = _results.length;
    final skipped = total - ran;

    buf.writeln();
    buf.writeln('  SUMMARY');
    buf.writeln('  ├─ Total    : $total tests');
    buf.writeln('  ├─ Passed   : $_passCount');
    buf.writeln('  ├─ Failed   : $_failCount');
    if (skipped > 0) buf.writeln('  ├─ Skipped  : $skipped');
    buf.writeln('  ├─ Duration : ${_totalDurationMs}ms (${(_totalDurationMs / 1000).toStringAsFixed(1)}s)');
    buf.writeln('  └─ Result   : ${_failCount == 0 && ran == total ? '✅ ALL PASSED' : '❌ FAILURES DETECTED'}');
    buf.writeln();

    // Failures detail
    final failures = _tests.where((t) {
      final r = _results[t.name];
      return r != null && !r.passed;
    }).toList();

    if (failures.isNotEmpty) {
      buf.writeln('  FAILED TESTS:');
      for (final t in failures) {
        final r = _results[t.name]!;
        buf.writeln('    ✗ ${t.name} (${r.durationMs}ms)');
        buf.writeln('      ${r.message}');
      }
      buf.writeln();
    }

    return buf.toString();
  }

  /// Save the test report to the device's documents directory.
  Future<String?> saveReport() async {
    if (_results.isEmpty) return null;
    try {
      final dir = await getApplicationDocumentsDirectory();
      final reportDir = Directory('${dir.path}/excel_plus_test_reports');
      if (!reportDir.existsSync()) reportDir.createSync(recursive: true);

      final now = DateTime.now();
      final fileName =
          'test_report_${now.year}${now.month.toString().padLeft(2, '0')}${now.day.toString().padLeft(2, '0')}_'
          '${now.hour.toString().padLeft(2, '0')}${now.minute.toString().padLeft(2, '0')}${now.second.toString().padLeft(2, '0')}.txt';

      final file = File('${reportDir.path}/$fileName');
      final report = generateReport();
      await file.writeAsString(report);

      _lastReportPath = file.path;
      debugPrint('Report saved: ${file.path}');
      return file.path;
    } catch (e) {
      debugPrint('Failed to save report: $e');
      return null;
    }
  }

  String? _lastReportPath;
  String? get lastReportPath => _lastReportPath;

  Future<void> _runSingle(int index) async {
    setState(() {
      _running = true;
      _currentIndex = index;
    });

    final result = await _tests[index].run();
    setState(() {
      _results[_tests[index].name] = result;
      _running = false;
      _currentIndex = -1;
      _passCount = _results.values.where((r) => r != null && r.passed).length;
      _failCount =
          _results.values.where((r) => r != null && !r.passed).length;
      _totalDurationMs =
          _results.values.fold(0, (sum, r) => sum + (r?.durationMs ?? 0));
    });
  }

  /// Expose results for integration test assertions.
  Map<String, TestResult?> get results => _results;
  int get passCount => _passCount;
  int get failCount => _failCount;
  bool get isRunning => _running;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('excel_plus Tests'),
        actions: [
          if (_results.isNotEmpty)
            Center(
              child: Padding(
                padding: const EdgeInsets.only(right: 16),
                child: Text(
                  '$_passCount✓  $_failCount✗  ${_totalDurationMs}ms',
                  style: const TextStyle(fontSize: 14),
                ),
              ),
            ),
        ],
      ),
      body: ListView.builder(
        key: const Key('test_list'),
        itemCount: _tests.length,
        itemBuilder: (context, index) {
          final test = _tests[index];
          final result = _results[test.name];
          final isCurrentlyRunning = _running && _currentIndex == index;

          return Card(
            key: Key('test_card_${test.name}'),
            margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
            child: ListTile(
              leading: _buildIcon(result, isCurrentlyRunning),
              title: Text(test.description),
              subtitle: result != null
                  ? Text(
                      result.message,
                      style: TextStyle(
                        color: result.passed
                            ? Colors.green[700]
                            : Colors.red[700],
                        fontSize: 12,
                      ),
                      maxLines: 2,
                      overflow: TextOverflow.ellipsis,
                    )
                  : Text(test.name,
                      style:
                          TextStyle(color: Colors.grey[500], fontSize: 12)),
              trailing: result != null
                  ? Text('${result.durationMs}ms',
                      style: const TextStyle(fontSize: 12))
                  : null,
              onTap: _running ? null : () => _runSingle(index),
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton.extended(
        key: const Key('run_all_button'),
        onPressed: _running ? null : runAll,
        icon: _running
            ? const SizedBox(
                width: 20,
                height: 20,
                child: CircularProgressIndicator(strokeWidth: 2))
            : const Icon(Icons.play_arrow),
        label: Text(_running ? 'Running...' : 'Run All'),
      ),
    );
  }

  Widget _buildIcon(TestResult? result, bool isRunning) {
    if (isRunning) {
      return const SizedBox(
        width: 24,
        height: 24,
        child: CircularProgressIndicator(strokeWidth: 2),
      );
    }
    if (result == null) {
      return const Icon(Icons.circle_outlined, color: Colors.grey);
    }
    return result.passed
        ? const Icon(Icons.check_circle, color: Colors.green)
        : const Icon(Icons.error, color: Colors.red);
  }
}
1
likes
0
points
144
downloads

Publisher

verified publisheralmasum.dev

Weekly Downloads

A fast, memory-efficient Dart library for reading, creating, and editing Excel (.xlsx) files.

Repository (GitHub)
View/report issues

Topics

#excel #xlsx #spreadsheet #office #dart

License

unknown (license)

Dependencies

archive, collection, equatable, web, xml

More

Packages that depend on excel_plus