/// 화면 메타데이터 class ScreenMetadata { final String screenName; final Type controllerType; final List relatedEndpoints; final Map screenCapabilities; ScreenMetadata({ required this.screenName, required this.controllerType, required this.relatedEndpoints, required this.screenCapabilities, }); Map toJson() => { 'screenName': screenName, 'controllerType': controllerType.toString(), 'relatedEndpoints': relatedEndpoints.map((e) => e.toJson()).toList(), 'screenCapabilities': screenCapabilities, }; } /// API 엔드포인트 class ApiEndpoint { final String path; final String method; final String description; final Map? parameters; final Map? headers; ApiEndpoint({ required this.path, required this.method, required this.description, this.parameters, this.headers, }); Map toJson() => { 'path': path, 'method': method, 'description': description, 'parameters': parameters, 'headers': headers, }; } /// 테스트 가능한 기능 class TestableFeature { final String featureName; final FeatureType type; final List testCases; final Map metadata; final Type? requiredDataType; final Map? dataConstraints; TestableFeature({ required this.featureName, required this.type, required this.testCases, required this.metadata, this.requiredDataType, this.dataConstraints, }); } /// 기능 타입 enum FeatureType { crud, search, filter, pagination, authentication, export, import, custom, } /// 테스트 케이스 class TestCase { final String name; final Future Function(TestData data) execute; final Future Function(TestData data) verify; final Future Function(TestData data)? setup; final Future Function(TestData data)? teardown; final Map? metadata; TestCase({ required this.name, required this.execute, required this.verify, this.setup, this.teardown, this.metadata, }); } /// 테스트 데이터 class TestData { final String dataType; final dynamic data; final Map metadata; TestData({ required this.dataType, required this.data, required this.metadata, }); Map toJson() => { 'dataType': dataType, 'data': data is Map || data is List ? data : data?.toJson() ?? {}, 'metadata': metadata, }; } /// 데이터 요구사항 class DataRequirement { final Type dataType; final Map constraints; final List relationships; final int quantity; DataRequirement({ required this.dataType, required this.constraints, required this.relationships, required this.quantity, }); } /// 필드 제약조건 class FieldConstraint { final bool required; final bool nullable; final int? minLength; final int? maxLength; final num? minValue; final num? maxValue; final String? pattern; final List? allowedValues; final String? defaultValue; FieldConstraint({ this.required = true, this.nullable = false, this.minLength, this.maxLength, this.minValue, this.maxValue, this.pattern, this.allowedValues, this.defaultValue, }); } /// 데이터 관계 class DataRelationship { final String name; final Type targetType; final RelationType type; final String targetId; final int? count; final Map? constraints; DataRelationship({ required this.name, required this.targetType, required this.type, required this.targetId, this.count, this.constraints, }); } /// 관계 타입 enum RelationType { oneToOne, oneToMany, manyToMany, } /// 생성 전략 class GenerationStrategy { final Type dataType; final List fields; final List relationships; final Map constraints; final int? quantity; GenerationStrategy({ required this.dataType, required this.fields, required this.relationships, required this.constraints, this.quantity, }); } /// 필드 생성 전략 class FieldGeneration { final String fieldName; final Type valueType; final String strategy; final String? prefix; final String? format; final List? pool; final String? relatedTo; final List? values; final dynamic value; FieldGeneration({ required this.fieldName, required this.valueType, required this.strategy, this.prefix, this.format, this.pool, this.relatedTo, this.values, this.value, }); } /// 필드 정의 class FieldDefinition { final String name; final FieldType type; final dynamic Function() generator; final bool required; final bool nullable; FieldDefinition({ required this.name, required this.type, required this.generator, this.required = true, this.nullable = false, }); } /// 필드 타입 enum FieldType { string, integer, double, boolean, dateTime, date, time, object, array, } /// 테스트 결과 class TestResult { final String screenName; final DateTime startTime; DateTime? endTime; final List featureResults = []; final List errors = []; final Map metrics = {}; TestResult({ required this.screenName, required this.startTime, this.endTime, }); bool get success => errors.isEmpty && featureResults.every((r) => r.success); bool get passed => success; // 호환성을 위한 별칭 Duration get duration => endTime != null ? endTime!.difference(startTime) : Duration.zero; // 테스트 카운트 관련 getter들 int get totalTests => featureResults .expand((r) => r.testCaseResults) .length; int get passedTests => featureResults .expand((r) => r.testCaseResults) .where((r) => r.success) .length; int get failedTests => totalTests - passedTests; void calculateMetrics() { metrics['totalFeatures'] = featureResults.length; metrics['successfulFeatures'] = featureResults.where((r) => r.success).length; metrics['failedFeatures'] = featureResults.where((r) => !r.success).length; metrics['totalTestCases'] = featureResults .expand((r) => r.testCaseResults) .length; metrics['successfulTestCases'] = featureResults .expand((r) => r.testCaseResults) .where((r) => r.success) .length; metrics['averageDuration'] = _calculateAverageDuration(); } double _calculateAverageDuration() { final allDurations = featureResults .expand((r) => r.testCaseResults) .map((r) => r.duration.inMilliseconds); if (allDurations.isEmpty) return 0; return allDurations.reduce((a, b) => a + b) / allDurations.length; } Map toJson() => { 'screenName': screenName, 'success': success, 'startTime': startTime.toIso8601String(), 'endTime': endTime?.toIso8601String(), 'duration': duration.inMilliseconds, 'featureResults': featureResults.map((r) => r.toJson()).toList(), 'errors': errors.map((e) => e.toJson()).toList(), 'metrics': metrics, }; } /// 기능 테스트 결과 class FeatureTestResult { final String featureName; final DateTime startTime; DateTime? endTime; final List testCaseResults = []; final Map metrics = {}; FeatureTestResult({ required this.featureName, required this.startTime, this.endTime, }); bool get success => testCaseResults.every((r) => r.success); Duration get duration => endTime != null ? endTime!.difference(startTime) : Duration.zero; void calculateMetrics() { metrics['totalTestCases'] = testCaseResults.length; metrics['successfulTestCases'] = testCaseResults.where((r) => r.success).length; metrics['failedTestCases'] = testCaseResults.where((r) => !r.success).length; metrics['averageDuration'] = _calculateAverageDuration(); } double _calculateAverageDuration() { if (testCaseResults.isEmpty) return 0; final totalMs = testCaseResults .map((r) => r.duration.inMilliseconds) .reduce((a, b) => a + b); return totalMs / testCaseResults.length; } Map toJson() => { 'featureName': featureName, 'success': success, 'startTime': startTime.toIso8601String(), 'endTime': endTime?.toIso8601String(), 'duration': duration.inMilliseconds, 'testCaseResults': testCaseResults.map((r) => r.toJson()).toList(), 'metrics': metrics, }; } /// 테스트 케이스 결과 class TestCaseResult { final String testCaseName; final bool success; final Duration duration; final String? error; final StackTrace? stackTrace; final Map? metadata; TestCaseResult({ required this.testCaseName, required this.success, required this.duration, this.error, this.stackTrace, this.metadata, }); Map toJson() => { 'testCaseName': testCaseName, 'success': success, 'duration': duration.inMilliseconds, 'error': error, 'stackTrace': stackTrace?.toString(), 'metadata': metadata, }; } /// 테스트 에러 class TestError { final String message; final StackTrace? stackTrace; final String? feature; final DateTime timestamp; final Map? context; TestError({ required this.message, this.stackTrace, this.feature, required this.timestamp, this.context, }); Map toJson() => { 'message': message, 'stackTrace': stackTrace?.toString(), 'feature': feature, 'timestamp': timestamp.toIso8601String(), 'context': context, }; }