xp_nix/test/simulation/simple_simulation_test.dart

188 lines
7.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:test/test.dart';
import 'package:sqlite3/sqlite3.dart';
import 'package:xp_nix/src/monitors/productivity_monitor.dart';
import '../../lib/src/testing/mock_idle_monitor.dart';
import '../../lib/src/testing/mock_activity_detector.dart';
import '../../lib/src/testing/mock_time_provider.dart';
import '../../lib/src/testing/mock_desktop_enhancer.dart';
import '../../lib/src/config/config_manager.dart';
void main() {
group('Simple Productivity Simulation Tests', () {
late Database db;
late ProductivityMonitor monitor;
late MockIdleMonitor mockIdleMonitor;
late MockActivityDetector mockActivityDetector;
late MockTimeProvider mockTimeProvider;
late MockDesktopEnhancer mockDesktopEnhancer;
setUp(() async {
// Create in-memory database for testing
db = sqlite3.openInMemory();
// Reset and initialize ConfigManager with default config
ConfigManager.resetInstance();
await ConfigManager.instance.initialize('/tmp/test_config_${DateTime.now().millisecondsSinceEpoch}.json');
// Create mock dependencies
mockIdleMonitor = MockIdleMonitor();
mockActivityDetector = MockActivityDetector();
mockTimeProvider = MockTimeProvider();
mockDesktopEnhancer = MockDesktopEnhancer();
// Set up starting time (Monday 9 AM)
mockTimeProvider.setTime(DateTime(2024, 1, 1, 9, 0));
// Create testable monitor with mocked dependencies
monitor = ProductivityMonitor(
db: db,
idleMonitor: mockIdleMonitor,
activityDetector: mockActivityDetector,
timeProvider: mockTimeProvider,
desktopEnhancer: mockDesktopEnhancer,
);
});
tearDown(() async {
monitor.stop();
// Add a small delay to allow async operations to complete
await Future.delayed(Duration(milliseconds: 100));
try {
db.dispose();
} catch (e) {
// Database might already be closed, ignore the error
}
});
test('simulates basic coding session with XP calculation', () async {
// Start the monitor
monitor.start();
await Future.delayed(Duration(milliseconds: 10));
print('\n💻 Starting coding session...');
// Simulate 1 hour of coding
mockActivityDetector.simulateActivity('vscode', 'main.dart - TestProject');
await Future.delayed(Duration(milliseconds: 1)); // Allow event to be processed
mockTimeProvider.advanceTime(Duration(minutes: 60));
monitor.flushCurrentActivity();
// Check stats
final stats = monitor.getTodayStats();
print(
'📊 Stats: ${stats['xp']} XP, Level ${stats['level']}, ${(stats['focus_time'] / 3600).toStringAsFixed(1)}h focus',
);
// Verify XP was earned
expect(stats['xp'], greaterThan(0), reason: 'Should have earned XP from coding');
expect(stats['focus_time'], greaterThan(0), reason: 'Should have focus time from coding');
expect(stats['level'], greaterThanOrEqualTo(1), reason: 'Should have at least level 1');
// Expected: 60 minutes * 10 XP/min = 600 XP (plus any time multipliers)
expect(stats['xp'], greaterThan(500), reason: 'Should have substantial XP from 1 hour coding');
print('✅ Basic coding session test passed!');
});
test('simulates mixed activity day', () async {
monitor.start();
await Future.delayed(Duration(milliseconds: 10));
print('\n🔄 Simulating mixed activity day...');
// Morning coding (2 hours)
mockActivityDetector.simulateActivity('vscode', 'feature.dart');
await Future.delayed(Duration(milliseconds: 1));
mockTimeProvider.advanceTime(Duration(minutes: 120));
monitor.flushCurrentActivity();
// Meeting (1 hour)
mockActivityDetector.simulateActivity('zoom', 'Team Meeting');
await Future.delayed(Duration(milliseconds: 1));
mockTimeProvider.advanceTime(Duration(minutes: 60));
monitor.flushCurrentActivity();
// Research (30 minutes)
mockActivityDetector.simulateActivity('firefox', 'Documentation - dart.dev');
await Future.delayed(Duration(milliseconds: 1));
mockTimeProvider.advanceTime(Duration(minutes: 30));
monitor.flushCurrentActivity();
final stats = monitor.getTodayStats();
print('📊 Mixed day stats: ${stats['xp']} XP, Level ${stats['level']}');
print(
' Focus: ${(stats['focus_time'] / 3600).toStringAsFixed(1)}h, Meetings: ${(stats['meeting_time'] / 3600).toStringAsFixed(1)}h',
);
// Verify different activity types
expect(stats['xp'], greaterThan(1000), reason: 'Should have substantial XP from mixed activities');
expect(stats['focus_time'], greaterThan(0), reason: 'Should have focus time from coding and research');
expect(stats['meeting_time'], greaterThan(0), reason: 'Should have meeting time from zoom');
print('✅ Mixed activity day test passed!');
});
test('demonstrates XP calculation accuracy', () async {
monitor.start();
await Future.delayed(Duration(milliseconds: 10));
print('\n🧮 Testing XP calculation accuracy...');
// Test different activity types with known durations
final activities = [
('vscode', 'coding', 30, 10), // 30 min coding at 10 XP/min = 300 XP
('firefox', 'research', 20, 6), // 20 min research at 6 XP/min = 120 XP
('slack', 'collaboration', 15, 7), // 15 min collaboration at 7 XP/min = 105 XP
('zoom', 'meeting', 60, 3), // 60 min meeting at 3 XP/min = 180 XP
];
int expectedTotalXP = 0;
for (final (app, description, minutes, xpPerMin) in activities) {
mockActivityDetector.simulateActivity(app, description);
await Future.delayed(Duration(milliseconds: 1));
mockTimeProvider.advanceTime(Duration(minutes: minutes));
monitor.flushCurrentActivity();
expectedTotalXP += minutes * xpPerMin;
print(' $description: $minutes min × $xpPerMin XP/min = ${minutes * xpPerMin} XP');
}
final stats = monitor.getTodayStats();
final actualXP = stats['xp'] as int;
print('📊 Expected: ~$expectedTotalXP XP, Actual: $actualXP XP');
// Allow for time multipliers (should be close to expected)
expect(actualXP, greaterThan(expectedTotalXP * 0.8), reason: 'XP should be reasonably close to expected');
expect(actualXP, lessThan(expectedTotalXP * 2.0), reason: 'XP should not be wildly inflated');
print('✅ XP calculation accuracy test passed!');
});
test('verifies level progression', () async {
monitor.start();
await Future.delayed(Duration(milliseconds: 10));
print('\n📈 Testing level progression...');
// Simulate enough activity to level up (need 100+ XP per level)
for (int i = 0; i < 5; i++) {
mockActivityDetector.simulateActivity('vscode', 'level_up_test_$i.dart');
await Future.delayed(Duration(milliseconds: 1));
mockTimeProvider.advanceTime(Duration(minutes: 30)); // 30 min * 10 XP/min = 300 XP
monitor.flushCurrentActivity();
final stats = monitor.getTodayStats();
print(' Session ${i + 1}: ${stats['xp']} XP, Level ${stats['level']}');
}
final finalStats = monitor.getTodayStats();
expect(finalStats['level'], greaterThan(1), reason: 'Should have leveled up');
expect(finalStats['xp'], greaterThan(1000), reason: 'Should have substantial XP');
print('✅ Level progression test passed!');
});
});
}