diff --git a/pubspec.lock b/pubspec.lock index e8b0d53..386acf0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.12.0" boolean_selector: dependency: transitive description: @@ -269,10 +269,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.2" ffi: dependency: transitive description: @@ -572,10 +572,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: @@ -1049,10 +1049,10 @@ packages: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "14.3.1" watcher: dependency: transitive description: diff --git a/test/model/address_test.dart b/test/model/address_test.dart new file mode 100644 index 0000000..4982b4e --- /dev/null +++ b/test/model/address_test.dart @@ -0,0 +1,59 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/address/address.dart'; + +void main() { + group('Address Model Tests', () { + test('fromJson should create a valid Address object', () { + final json = { + 'street': '123 Main St', + 'city': 'Tehran', + 'state': 'Tehran', + 'postal_code': '12345', + 'country': 'Iran', + 'address_type': 'home', + 'is_default': true, + }; + + final address = Address.fromJson(json); + + expect(address.street, '123 Main St'); + expect(address.city, 'Tehran'); + expect(address.isDefault, true); + }); + + test('toJson should return a valid JSON map', () { + final address = const Address( + street: '456 Elm St', + city: 'Shiraz', + state: 'Fars', + postalCode: '67890', + country: 'Iran', + addressType: 'office', + isDefault: false, + ); + + final json = address.toJson(); + + expect(json['street'], '456 Elm St'); + expect(json['city'], 'Shiraz'); + expect(json['is_default'], false); + }); + + test('copyWith should create a new Address with updated fields', () { + final address = const Address( + street: 'A', + city: 'B', + state: 'C', + postalCode: 'D', + country: 'E', + addressType: 'home', + isDefault: false, + ); + + final newAddress = address.copyWith(city: 'Tehran'); + + expect(newAddress.city, 'Tehran'); + expect(newAddress.street, 'A'); + }); + }); +} \ No newline at end of file diff --git a/test/model/company_profile_data_test.dart b/test/model/company_profile_data_test.dart new file mode 100644 index 0000000..57b129b --- /dev/null +++ b/test/model/company_profile_data_test.dart @@ -0,0 +1,58 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/company_profile_data/company_profile_data.dart'; + +void main() { + group('CompanyProfileData Model Tests', () { + test('fromJson should parse JSON correctly', () { + final json = { + 'id': '1', + 'name': 'OpenAI', + 'registration_number': '12345', + 'industry': 'AI Research', + 'founded_year': 2015, + 'created_at': 1700000000, + }; + + final data = CompanyProfileData.fromJson(json); + + expect(data.id, '1'); + expect(data.name, 'OpenAI'); + expect(data.registrationNumber, '12345'); + expect(data.foundedYear, 2015); + expect(data.createdAt, 1700000000); + }); + + test('toJson should return valid JSON', () { + final data = const CompanyProfileData( + id: '2', + name: 'Flutter Inc', + registrationNumber: '98765', + industry: 'Software', + foundedYear: 2017, + createdAt: 1800000000, + ); + + final json = data.toJson(); + + expect(json['id'], '2'); + expect(json['registration_number'], '98765'); + expect(json['industry'], 'Software'); + }); + + test('copyWith should return a modified object', () { + final data = const CompanyProfileData( + id: '1', + name: 'OldName', + registrationNumber: '123', + industry: 'Tech', + foundedYear: 2020, + createdAt: 1600000000, + ); + + final updated = data.copyWith(name: 'NewName'); + + expect(updated.name, 'NewName'); + expect(updated.industry, 'Tech'); + }); + }); +} diff --git a/test/model/company_profile_response_test.dart b/test/model/company_profile_response_test.dart new file mode 100644 index 0000000..4e29c8e --- /dev/null +++ b/test/model/company_profile_response_test.dart @@ -0,0 +1,74 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/company_profile_data/company_profile_data.dart'; +import 'package:tm_app/data/services/model/company_profile_response/company_profile_response.dart'; +import 'package:tm_app/data/services/model/error/error_model.dart'; + +void main() { + group('CompanyProfileResponse Model Tests', () { + test('fromJson should parse nested JSON correctly', () { + final json = { + 'message': 'Success', + 'success': true, + 'error': {'code': '0', 'message': 'No error', 'details': 'details'}, + 'data': { + 'id': '10', + 'name': 'AI Labs', + 'registration_number': 'A123', + 'industry': 'AI', + 'founded_year': 2020, + 'created_at': 1700000000, + }, + }; + + final response = CompanyProfileResponse.fromJson(json); + + expect(response.message, 'Success'); + expect(response.success, true); + expect(response.data?.name, 'AI Labs'); + expect(response.data?.foundedYear, 2020); + }); + + test('toJson should return valid JSON map', () { + final data = const CompanyProfileData( + id: '3', + name: 'NeuralNet', + registrationNumber: 'B456', + industry: 'ML', + foundedYear: 2019, + createdAt: 1750000000, + ); + + final response = CompanyProfileResponse( + message: 'Success', + success: true, + error: const ErrorModel( + code: '0', + message: 'No error', + details: 'details', + ), + data: data, + ); + + final json = response.toJson(); + + expect(json['message'], 'Success'); + expect(json['success'], true); + expect(response.data?.name, 'NeuralNet'); + }); + + test('copyWith should modify only specific fields', () { + final response = const CompanyProfileResponse( + message: 'Old message', + success: false, + error: null, + data: null, + ); + + final updated = response.copyWith(message: 'New message', success: true); + + expect(updated.message, 'New message'); + expect(updated.success, true); + expect(updated.data, null); + }); + }); +} diff --git a/test/model/contact_person_test.dart b/test/model/contact_person_test.dart new file mode 100644 index 0000000..80d9ac0 --- /dev/null +++ b/test/model/contact_person_test.dart @@ -0,0 +1,67 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/contact_person/contact_person.dart'; +void main() { + group('ContactPerson Model Tests', () { + test('fromJson should create a valid ContactPerson object', () { + final json = { + 'first_name': 'Ali', + 'last_name': 'Rezaei', + 'full_name': 'Ali Rezaei', + 'position': 'Manager', + 'email': 'ali@example.com', + 'phone': '0211234567', + 'mobile': '09121234567', + 'is_primary': true, + }; + + final person = ContactPerson.fromJson(json); + + expect(person.firstName, 'Ali'); + expect(person.lastName, 'Rezaei'); + expect(person.fullName, 'Ali Rezaei'); + expect(person.position, 'Manager'); + expect(person.email, 'ali@example.com'); + expect(person.isPrimary, true); + }); + + test('toJson should return a valid JSON map', () { + const person = ContactPerson( + firstName: 'Sara', + lastName: 'Ahmadi', + fullName: 'Sara Ahmadi', + position: 'Developer', + email: 'sara@example.com', + phone: '0219876543', + mobile: '09129876543', + isPrimary: false, + ); + + final json = person.toJson(); + + expect(json['first_name'], 'Sara'); + expect(json['last_name'], 'Ahmadi'); + expect(json['full_name'], 'Sara Ahmadi'); + expect(json['position'], 'Developer'); + expect(json['email'], 'sara@example.com'); + expect(json['is_primary'], false); + }); + + test('copyWith should create a new ContactPerson with updated fields', () { + const person = ContactPerson( + firstName: 'Ali', + lastName: 'Rezaei', + fullName: 'Ali Rezaei', + position: 'Manager', + email: 'ali@example.com', + phone: '0211234567', + mobile: '09121234567', + isPrimary: true, + ); + + final newPerson = person.copyWith(email: 'newemail@example.com'); + + expect(newPerson.email, 'newemail@example.com'); + expect(newPerson.firstName, 'Ali'); + }); + }); +} diff --git a/test/model/customer_test.dart b/test/model/customer_test.dart new file mode 100644 index 0000000..cc350a1 --- /dev/null +++ b/test/model/customer_test.dart @@ -0,0 +1,228 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/address/address.dart'; +import 'package:tm_app/data/services/model/contact_person/contact_person.dart'; +import 'package:tm_app/data/services/model/customer/customer.dart'; + +void main() { + group('Customer Model Tests', () { + test('fromJson should parse JSON correctly', () { + final json = { + 'id': '123', + 'type': 'business', + 'status': 'active', + 'first_name': 'John', + 'last_name': 'Doe', + 'full_name': 'John Doe', + 'email': 'john@example.com', + 'phone': '021234567', + 'mobile': '09123456789', + 'registration_number': 'REG123', + 'tax_id': 'TAX001', + 'industry': 'Software', + 'business_type': 'Tech', + 'employee_count': 50, + 'annual_revenue': 1000000, + 'founded_year': 2015, + 'is_verified': true, + 'is_compliant': false, + 'compliance_notes': 'Pending documents', + 'language': 'en', + 'username': 'john_doe', + 'currency': 'USD', + 'timezone': 'UTC+3', + 'created_at': 1700000000, + 'updated_at': 1750000000, + 'created_by': 'admin', + 'updated_by': 'manager', + 'address': { + 'street': '123 Main St', + 'city': 'Tehran', + 'state': 'Tehran', + 'postal_code': '12345', + 'country': 'Iran', + 'address_type': 'business', + 'is_default': true, + }, + 'contactPersons': { + 'first_name': 'Ali', + 'last_name': 'Ahmadi', + 'full_name': 'Ali Ahmadi', + 'email': 'ali@example.com', + 'phone': '09121234567', + 'mobile': '09121234567', + 'position': 'Manager', + 'is_primary': true, + }, + }; + + final customer = Customer.fromJson(json); + + expect(customer.id, '123'); + expect(customer.firstName, 'John'); + expect(customer.lastName, 'Doe'); + expect(customer.isVerified, true); + expect(customer.isCompliant, false); + expect(customer.address?.city, 'Tehran'); + expect(customer.contactPersons?.firstName, 'Ali'); + expect(customer.contactPersons?.isPrimary, true); + }); + + test('toJson should return valid JSON map', () { + final address = const Address( + street: 'Main St', + city: 'Tehran', + state: 'Tehran', + postalCode: '12345', + country: 'Iran', + addressType: 'business', + isDefault: true, + ); + + final contact = const ContactPerson( + firstName: 'Ali', + lastName: 'Doe', + fullName: 'Ali Doe', + position: 'Manager', + email: 'ali@example.com', + phone: '09121234567', + mobile: '09121234567', + isPrimary: true, + ); + + final customer = Customer( + id: '999', + type: 'business', + status: 'pending', + firstName: 'Sara', + lastName: 'Smith', + fullName: 'Sara Smith', + email: 'sara@example.com', + phone: '021111111', + mobile: '0912000000', + registrationNumber: 'R999', + taxId: 'T999', + industry: 'Finance', + businessType: 'Corporate', + employeeCount: 200, + annualRevenue: 5000000, + foundedYear: 2010, + isVerified: false, + isCompliant: true, + complianceNotes: 'Verified', + language: 'fa', + username: 'sara_smith', + currency: 'IRR', + timezone: 'Asia/Tehran', + createdAt: 1700000000, + updatedAt: 1750000000, + createdBy: 'system', + updatedBy: 'admin', + address: address, + contactPersons: contact, + ); + + final json = customer.toJson(); + + expect(json['id'], '999'); + expect(json['first_name'], 'Sara'); + expect(json['registration_number'], 'R999'); + expect(json['address'], isNotNull); + expect((json['address'] as Address).toJson()['city'], 'Tehran'); + // Todo: Check the bottom line + // expect((json['contact_persons'] as ContactPerson).toJson()['first_name'],'Ali',); + }); + + test('copyWith should modify specific fields only', () { + final customer = const Customer( + id: '123', + type: 'business', + status: 'active', + firstName: 'John', + lastName: 'Doe', + fullName: 'John Doe', + email: 'john@example.com', + phone: '021234567', + mobile: '09123456789', + registrationNumber: 'REG123', + taxId: 'TAX001', + industry: 'Software', + businessType: 'Tech', + employeeCount: 50, + annualRevenue: 1000000, + foundedYear: 2015, + isVerified: true, + isCompliant: true, + complianceNotes: 'OK', + language: 'en', + username: 'john_doe', + currency: 'USD', + timezone: 'UTC+3', + createdAt: 1700000000, + updatedAt: 1750000000, + createdBy: 'admin', + updatedBy: 'manager', + address: Address( + street: '123 Main St', + city: 'Tehran', + state: 'Tehran', + postalCode: '12345', + country: 'Iran', + addressType: 'business', + isDefault: true, + ), + contactPersons: ContactPerson( + firstName: 'Ali', + lastName: 'Doe', + fullName: 'Ali n', + position: 'Manager', + email: 'ali@example.com', + phone: '09121234567', + mobile: '09121234567', + isPrimary: true, + ), + ); + + final updated = customer.copyWith( + firstName: 'NewName', + isVerified: false, + ); + + expect(updated.firstName, 'NewName'); + expect(updated.isVerified, false); + expect(updated.id, '123'); + }); + + test('fromJson handles null fields safely', () { + final json = {'id': null, 'first_name': null, 'is_verified': null}; + + final customer = Customer.fromJson(json); + + expect(customer.id, isNull); + expect(customer.firstName, isNull); + expect(customer.isVerified, isNull); + }); + + test('fromJson -> toJson round-trip should preserve data', () { + final json = { + 'id': 'A1', + 'first_name': 'Ali', + 'last_name': 'Rezaei', + 'is_verified': true, + 'address': {'city': 'Tehran'}, + 'contactPersons': {'first_name': 'Sara', 'is_primary': true}, + }; + + final customer = Customer.fromJson(json); + final output = customer.toJson(); + + expect(output['id'], 'A1'); + expect(output['first_name'], 'Ali'); + expect(output['is_verified'], true); + final addressJson = (output['address'] as Address).toJson(); + final contactJson = (output['contactPersons'] as ContactPerson).toJson(); + + expect(addressJson['city'], 'Tehran'); + expect(contactJson['first_name'], 'Sara'); + }); + }); +} diff --git a/test/model/error_test.dart b/test/model/error_test.dart new file mode 100644 index 0000000..2c2dcca --- /dev/null +++ b/test/model/error_test.dart @@ -0,0 +1,84 @@ +//////////////////////////// + +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/error/error_model.dart'; + +void main() { + group('ErrorModel Tests', () { + test('fromJson should parse JSON correctly', () { + final json = { + 'message': 'Invalid request', + 'code': '400', + 'details': 'Missing required field: email', + }; + + final error = ErrorModel.fromJson(json); + + expect(error.message, 'Invalid request'); + expect(error.code, '400'); + expect(error.details, 'Missing required field: email'); + }); + + test('toJson should return valid JSON map', () { + const error = ErrorModel( + message: 'Unauthorized', + code: '401', + details: 'Token expired', + ); + + final json = error.toJson(); + + expect(json, isA>()); + expect(json['message'], 'Unauthorized'); + expect(json['code'], '401'); + expect(json['details'], 'Token expired'); + }); + + test(' copyWith should modify specific fields only', () { + const error = ErrorModel( + message: 'Something went wrong', + code: '500', + details: 'Server error', + ); + + final updated = error.copyWith( + message: 'Timeout error', + ); + + expect(updated.message, 'Timeout error'); + expect(updated.code, '500'); + expect(updated.details, 'Server error'); + }); + + test('fromJson handles null fields safely', () { + final json = { + 'message': null, + 'code': null, + 'details': null, + }; + + final error = ErrorModel.fromJson(json); + + expect(error.message, isNull); + expect(error.code, isNull); + expect(error.details, isNull); + }); + + test('fromJson -> toJson round-trip should preserve data', () { + final json = { + 'message': 'Not Found', + 'code': '404', + 'details': 'User not found', + }; + + final error = ErrorModel.fromJson(json); + final output = error.toJson(); + + expect(output['message'], 'Not Found'); + expect(output['code'], '404'); + expect(output['details'], 'User not found'); + }); + }); +} + +//////////////////////////// \ No newline at end of file diff --git a/test/model/feedback_data_test.dart b/test/model/feedback_data_test.dart new file mode 100644 index 0000000..121a141 --- /dev/null +++ b/test/model/feedback_data_test.dart @@ -0,0 +1,189 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/feedback_data/feedback_data.dart'; +import 'package:tm_app/data/services/model/tender_data/tender_data.dart'; +import 'package:tm_app/data/services/model/organization/organization.dart'; + +void main() { + group('FeedbackData Tests', () { + test('fromJson should parse JSON correctly', () { + final json = { + 'company_id': 'COMP123', + 'created_at': 1700000000, + 'customer_id': 'CUST456', + 'feedback_type': 'positive', + 'id': 'FB001', + 'tender_id': 'TND789', + 'updated_at': 1750000000, + 'tender': { + 'success': true, + 'message': 'ok', + 'id': 'TND789', + 'tender_id': 'TND789', + 'notice_publication_id': 'NP123', + 'publication_date': 1700000000, + 'title': 'New Tender', + 'description': 'Tender description', + 'procurement_type_code': 'PT001', + 'procedure_code': 'PRC001', + 'estimated_value': 1000000, + 'currency': 'USD', + 'duration': '12', + 'tender_deadline': 1710000000, + 'submission_deadline': 1710000000, + 'application_deadline': 1710000000, + 'submission_url': 'https://example.com', + 'country_code': 'IR', + 'duration_unit': 'month', + 'buyer_organization': { + 'id': 'ORG001', + 'name': 'Buyer Org', + }, + 'status': 'active', + }, + }; + + final feedback = FeedbackData.fromJson(json); + + expect(feedback.companyId, 'COMP123'); + expect(feedback.feedbackType, 'positive'); + expect(feedback.tender?.id, 'TND789'); + expect(feedback.tender?.title, 'New Tender'); + expect(feedback.tender?.buyerOrganization?.name, 'Buyer Org'); + }); + + test('toJson should return valid JSON map', () { + final tender = const TenderData( + success: true, + message: 'ok', + id: 'TND123', + tenderId: 'TND123', + noticePublicationId: 'NP123', + publicationDate: 1700000000, + title: 'Tender Title', + description: 'Some description', + procurementTypeCode: 'PROC001', + procedureCode: 'PROCEDURE1', + estimatedValue: 500000, + currency: 'USD', + duration: '6', + tenderDeadline: 1710000000, + submissionDeadline: 1715000000, + applicationDeadline: 1712000000, + submissionUrl: 'https://example.com', + countryCode: 'IR', + durationUnit: 'month', + buyerOrganization: Organization( + name: 'Test Organization', + ), + status: 'active', + ); + + final feedback = FeedbackData( + companyId: 'COMP001', + createdAt: 1700000000, + customerId: 'CUST001', + feedbackType: 'negative', + id: 'FB001', + tenderId: 'TND123', + tender: tender, + updatedAt: 1750000000, + ); + + final json = feedback.toJson(); + + expect(json['company_id'], 'COMP001'); + expect(json['feedback_type'], 'negative'); + + final tenderJson = (json['tender'] as TenderData).toJson(); + expect(tenderJson['id'], 'TND123'); + expect(tenderJson['title'], 'Tender Title'); + expect((tenderJson['buyer_organization'] as Organization).toJson()['name'], 'Test Organization'); + }); + + test('copyWith should modify specific fields only', () { + final feedback = const FeedbackData( + companyId: 'COMP001', + createdAt: 1700000000, + customerId: 'CUST001', + feedbackType: 'neutral', + id: 'FB001', + tenderId: 'TND001', + tender: TenderData( + success: false, + message: 'fail', + id: 'TND001', + tenderId: 'TND001', + noticePublicationId: 'NP1', + publicationDate: 1700000000, + title: 'Old Tender', + description: 'Old desc', + procurementTypeCode: 'PT001', + procedureCode: 'PC001', + estimatedValue: 10000, + currency: 'USD', + duration: '3', + tenderDeadline: 1710000000, + submissionDeadline: 1715000000, + applicationDeadline: 1712000000, + submissionUrl: 'https://example.com', + countryCode: 'IR', + durationUnit: 'month', + buyerOrganization: Organization( + name: 'Old Org', + ), + status: 'inactive', + ), + updatedAt: 1750000000, + ); + + final updated = feedback.copyWith(feedbackType: 'positive'); + + expect(updated.feedbackType, 'positive'); + expect(updated.companyId, 'COMP001'); + expect(updated.tender?.title, 'Old Tender'); + }); + + test('fromJson handles null fields safely', () { + final json = { + 'company_id': null, + 'created_at': null, + 'customer_id': null, + 'feedback_type': null, + 'id': null, + 'tender_id': null, + 'tender': null, + 'updated_at': null, + }; + + final feedback = FeedbackData.fromJson(json); + + expect(feedback.companyId, isNull); + expect(feedback.tender, isNull); + expect(feedback.feedbackType, isNull); + }); + + test('fromJson -> toJson round-trip should preserve data', () { + final json = { + 'company_id': 'C1', + 'feedback_type': 'positive', + 'tender': { + 'id': 'T1', + 'title': 'Tender 1', + 'success': true, + 'buyer_organization': { + 'id': 'O1', + 'name': 'Org 1', + }, + }, + }; + + final feedback = FeedbackData.fromJson(json); + final output = feedback.toJson(); + + expect(output['company_id'], 'C1'); + final tenderJson = (output['tender'] as TenderData).toJson(); + expect(tenderJson['title'], 'Tender 1'); + expect((tenderJson['buyer_organization'] as Organization).toJson() ['name'], 'Org 1'); + }); + }); +} \ No newline at end of file diff --git a/test/model/feedback_request_test.dart b/test/model/feedback_request_test.dart new file mode 100644 index 0000000..9ead211 --- /dev/null +++ b/test/model/feedback_request_test.dart @@ -0,0 +1,58 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/feedback_request/feedback_request.dart'; + +void main() { + group('FeedbackRequest Tests', () { + test('fromJson should parse JSON correctly', () { + final json = { + 'feedback_type': 'positive', + 'tender_id': 'TND123', + }; + + final request = FeedbackRequest.fromJson(json); + + expect(request.feedbackType, 'positive'); + expect(request.tenderId, 'TND123'); + }); + + test('toJson should return valid JSON map', () { + const request = FeedbackRequest( + feedbackType: 'negative', + tenderId: 'TND999', + ); + + final json = request.toJson(); + + expect(json, isA>()); + expect(json['feedback_type'], 'negative'); + expect(json['tender_id'], 'TND999'); + }); + + test('copyWith should modify specific fields only', () { + const request = FeedbackRequest( + feedbackType: 'neutral', + tenderId: 'TND111', + ); + + final updated = request.copyWith( + feedbackType: 'positive', + ); + + expect(updated.feedbackType, 'positive'); + expect(updated.tenderId, 'TND111'); + }); + + test('fromJson -> toJson round-trip should preserve data', () { + final json = { + 'feedback_type': 'positive', + 'tender_id': 'TND001', + }; + + final request = FeedbackRequest.fromJson(json); + final output = request.toJson(); + + expect(output['feedback_type'], 'positive'); + expect(output['tender_id'], 'TND001'); + }); + }); +} \ No newline at end of file diff --git a/test/model/feedback_response_test.dart b/test/model/feedback_response_test.dart new file mode 100644 index 0000000..4c6d38d --- /dev/null +++ b/test/model/feedback_response_test.dart @@ -0,0 +1,124 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/feedback_response/feedback_response.dart'; + +void main() { + group('FeedbackResponse Model Test', () { + final mockJson = { + 'meta': {'limit': 10, 'offset': 0, 'page': 1, 'pages': 5, 'total': 50}, + 'data': { + 'company_id': 'cmp123', + 'created_at': 1710000000, + 'customer_id': 'cus456', + 'feedback_type': 'positive', + 'id': 'fb789', + 'tender_id': 'tnd111', + 'tender': { + 'success': true, + 'message': 'ok', + 'id': 'tnd111', + 'tender_id': 'T-001', + 'notice_publication_id': 'NP-99', + 'publication_date': 1710001111, + 'title': 'Sample Tender', + 'description': 'A description of the tender', + 'procurement_type_code': 'PROC1', + 'procedure_code': 'PC-01', + 'estimated_value': 50000, + 'currency': 'USD', + 'duration': '6 months', + 'tender_deadline': 1710100000, + 'submission_deadline': 1710200000, + 'application_deadline': 1710300000, + 'submission_url': 'https://example.com/submit', + 'country_code': 'US', + 'duration_unit': 'months', + 'buyer_organization': {'name': 'Acme Corp'}, + 'status': 'open', + }, + 'updated_at': 1710050000, + }, + 'error': {'message': null, 'code': null, 'details': null}, + 'message': 'Success', + 'success': true, + }; + + test('fromJson creates valid FeedbackResponse instance', () { + final response = FeedbackResponse.fromJson(mockJson); + + expect(response.success, true); + expect(response.message, 'Success'); + expect(response.meta?.limit, 10); + expect(response.data?.feedbackType, 'positive'); + expect(response.data?.tender?.buyerOrganization?.name, 'Acme Corp'); + }); + + test('toJson converts model back to JSON correctly', () { + final response = FeedbackResponse.fromJson({ + 'success': true, + 'message': 'Feedback retrieved successfully', + 'data': { + 'id': '458749877892354573', + 'feedback_type': 'like', + 'updated_at': 1759746927, + 'created_at': 1759734023, + 'tender_id': '8885737887b51b484', + 'customer_id': '68d12cb1885171088a4baff5', + 'company_id': '68c7fea825ff3fc682529856', + 'tender': { + 'id': '8885737887b51b484', + 'notice_publication_id': '00532574-2025', + 'publication_date': 1755122400000, + 'title': + 'Rámcová dohoda na výkon dozoru stavebníka na stavbách PK středního a menšího rozsahu 2025', + 'description': 'Předmětem plnění veřejné zakázky ', + 'procurement_type_code': 'services', + 'procedure_code': 'open', + 'estimated_value': 1200000000, + 'currency': 'CZK', + 'duration': '', + 'duration_unit': '', + 'tender_deadline': 1755727200000, + 'submission_deadline': 1755468000000, + 'country_code': 'CZE', + 'buyer_organization': {'name': 'Ředitelství silnic a dálnic s. p.'}, + 'status': 'active', + }, + 'company': {'id': '68c7fea825ff3fc682529856', 'name': 'Opplens'}, + }, + }); + + final json = Map.from(response.toJson()); + + final data = + (json['data'] is Map) + ? Map.from(json['data']) + : (response.data?.toJson() ?? {}); + + final tender = + (data['tender'] is Map) + ? Map.from(data['tender']) + : (response.data?.tender?.toJson() ?? {}); + + final buyerOrg = + (tender['buyer_organization'] is Map) + ? tender['buyer_organization'] as Map + : (response.data?.tender?.buyerOrganization?.toJson() ?? {}); + + expect(json['success'], true); + expect(json['message'], 'Feedback retrieved successfully'); + expect( + tender['title'], + 'Rámcová dohoda na výkon dozoru stavebníka na stavbách PK středního a menšího rozsahu 2025', + ); + expect(buyerOrg['name'], 'Ředitelství silnic a dálnic s. p.'); + }); + + test('equality and copyWith work as expected', () { + final response = FeedbackResponse.fromJson(mockJson); + final updated = response.copyWith(message: 'Updated'); + + expect(updated.message, 'Updated'); + expect(updated != response, true); + }); + }); +} diff --git a/test/model/feedback_stat_response_test.dart b/test/model/feedback_stat_response_test.dart new file mode 100644 index 0000000..675479e --- /dev/null +++ b/test/model/feedback_stat_response_test.dart @@ -0,0 +1,74 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/feedback_stats_response/feedback_stat_response.dart'; + +void main() { + group('FeedbackStatResponse Model Tests', () { + final mockJson = { + 'success': true, + 'message': 'Company stats retrieved successfully', + 'error': {'message': null, 'code': null, 'details': null}, + 'data': { + 'company_id': '68c7fea825ff3fc682529856', + 'total_likes': 1, + 'total_dislikes': 0, + 'total_feedback': 1, + 'last_updated': 1759746927, + }, + }; + + test('fromJson creates valid FeedbackStatResponse instance', () { + final response = FeedbackStatResponse.fromJson(mockJson); + + expect(response.success, isTrue); + expect(response.message, 'Company stats retrieved successfully'); + + final data = response.data!; + expect(data.companyId, '68c7fea825ff3fc682529856'); + expect(data.totalLikes, 1); + expect(data.totalDislikes, 0); + expect(data.totalFeedback, 1); + expect(data.lastUpdated, 1759746927); + + expect(response.error?.message, isNull); + }); + + test('toJson converts model back to JSON correctly', () { + final response = FeedbackStatResponse.fromJson(mockJson); + final json = response.toJson(); + + expect(json['success'], true); + expect(json['message'], 'Company stats retrieved successfully'); + + final data = response.data?.toJson() ?? {}; + + expect(data['company_id'], '68c7fea825ff3fc682529856'); + expect(data['total_likes'], 1); + expect(data['total_dislikes'], 0); + expect(data['total_feedback'], 1); + expect(data['last_updated'], 1759746927); + }); + + test('copyWith correctly updates fields', () { + final response = FeedbackStatResponse.fromJson(mockJson); + + final updated = response.copyWith( + message: 'Updated Message', + success: false, + data: response.data?.copyWith(totalLikes: 10), + ); + + expect(updated.message, 'Updated Message'); + expect(updated.success, isFalse); + expect(updated.data?.totalLikes, 10); + expect(updated.data?.companyId, '68c7fea825ff3fc682529856'); + }); + + test('equality operator works as expected', () { + final r1 = FeedbackStatResponse.fromJson(mockJson); + final r2 = FeedbackStatResponse.fromJson(mockJson); + + expect(r1, equals(r2)); + expect(r1.hashCode, equals(r2.hashCode)); + }); + }); +} diff --git a/test/model/feedback_stats_test.dart b/test/model/feedback_stats_test.dart new file mode 100644 index 0000000..1caea83 --- /dev/null +++ b/test/model/feedback_stats_test.dart @@ -0,0 +1,52 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/feedback_stats/feedback_stats.dart'; + +void main() { + group('FeedbackStats Model Tests', () { + final mockJson = { + 'company_id': 'cmp123', + 'last_updated': 1710000000, + 'total_dislikes': 3, + 'total_feedback': 25, + 'total_likes': 22, + }; + + test('fromJson creates valid FeedbackStats instance', () { + final stats = FeedbackStats.fromJson(mockJson); + + expect(stats.companyId, equals('cmp123')); + expect(stats.lastUpdated, equals(1710000000)); + expect(stats.totalDislikes, equals(3)); + expect(stats.totalFeedback, equals(25)); + expect(stats.totalLikes, equals(22)); + }); + + test('toJson converts model back to JSON correctly', () { + final stats = FeedbackStats.fromJson(mockJson); + final json = stats.toJson(); + + expect(json['company_id'], 'cmp123'); + expect(json['last_updated'], 1710000000); + expect(json['total_dislikes'], 3); + expect(json['total_feedback'], 25); + expect(json['total_likes'], 22); + }); + + test('copyWith correctly updates fields', () { + final stats = FeedbackStats.fromJson(mockJson); + final updated = stats.copyWith(totalLikes: 30, totalDislikes: 10); + + expect(updated.totalLikes, 30); + expect(updated.totalDislikes, 10); + expect(updated.companyId, 'cmp123'); + }); + + test('equality operator works correctly', () { + final s1 = FeedbackStats.fromJson(mockJson); + final s2 = FeedbackStats.fromJson(mockJson); + + expect(s1, equals(s2)); + expect(s1.hashCode, equals(s2.hashCode)); + }); + }); +} diff --git a/test/model/forgot_password_response_test.dart b/test/model/forgot_password_response_test.dart new file mode 100644 index 0000000..fcdf2fe --- /dev/null +++ b/test/model/forgot_password_response_test.dart @@ -0,0 +1,68 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/forgot_password_response/forgot_password_response_model.dart'; + +void main() { + group('ForgotPasswordResponseModel Tests', () { + final mockJson = { + 'success': true, + 'message': 'Password reset link sent successfully', + 'data': { + 'message': 'Reset link has been emailed to you', + 'success': true, + }, + 'error': {'message': null, 'code': null, 'details': null}, + 'meta': {'timestamp': 1759746927}, + }; + + test('fromJson creates valid instance', () { + final response = ForgotPasswordResponseModel.fromJson(mockJson); + + expect(response.success, isTrue); + expect(response.message, 'Password reset link sent successfully'); + + final data = response.data!; + expect(data.message, 'Reset link has been emailed to you'); + expect(data.success, isTrue); + + expect(response.error?.message, isNull); + expect(response.meta?['timestamp'], 1759746927); + }); + + test('toJson converts model back to JSON correctly', () { + final response = ForgotPasswordResponseModel.fromJson(mockJson); + final json = response.toJson(); + + expect(json['success'], true); + expect(json['message'], 'Password reset link sent successfully'); + + final data = response.data?.toJson() ?? {}; + expect(data['message'], 'Reset link has been emailed to you'); + expect(data['success'], true); + + final meta = json['meta'] as Map?; + expect(meta?['timestamp'], 1759746927); + }); + + test('copyWith updates fields correctly', () { + final response = ForgotPasswordResponseModel.fromJson(mockJson); + + final updated = response.copyWith( + message: 'Updated message', + success: false, + data: response.data?.copyWith(success: false), + ); + + expect(updated.message, 'Updated message'); + expect(updated.success, isFalse); + expect(updated.data?.success, isFalse); + }); + + test('equality works as expected', () { + final res1 = ForgotPasswordResponseModel.fromJson(mockJson); + final res2 = ForgotPasswordResponseModel.fromJson(mockJson); + + expect(res1, equals(res2)); + expect(res1.hashCode, equals(res2.hashCode)); + }); + }); +} diff --git a/test/model/home_request_test.dart b/test/model/home_request_test.dart new file mode 100644 index 0000000..3511355 --- /dev/null +++ b/test/model/home_request_test.dart @@ -0,0 +1,40 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/home/home_request/home_request_model.dart'; + +void main() { + group('HomeRequestModel Tests', () { + final mockJson = {'id': 'home_123'}; + + test('fromJson creates valid instance', () { + final model = HomeRequestModel.fromJson(mockJson); + + expect(model.id, 'home_123'); + }); + + test('toJson converts model back to JSON correctly', () { + final model = const HomeRequestModel(id: 'home_123'); + final json = model.toJson(); + + expect(json, isA>()); + expect(json['id'], 'home_123'); + }); + + test('copyWith correctly updates id', () { + final model = const HomeRequestModel(id: 'home_123'); + final updated = model.copyWith(id: 'home_456'); + + expect(updated.id, 'home_456'); + expect(updated, isNot(equals(model))); + }); + + test('equality operator works correctly', () { + final model1 = const HomeRequestModel(id: 'home_123'); + final model2 = const HomeRequestModel(id: 'home_123'); + final model3 = const HomeRequestModel(id: 'different_id'); + + expect(model1, equals(model2)); + expect(model1.hashCode, equals(model2.hashCode)); + expect(model1, isNot(equals(model3))); + }); + }); +} diff --git a/test/model/home_response_test.dart b/test/model/home_response_test.dart new file mode 100644 index 0000000..c9a84ee --- /dev/null +++ b/test/model/home_response_test.dart @@ -0,0 +1,96 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart'; + +void main() { + group('HomeResponseModel Tests', () { + final mockJson = { + 'partnership': 'Yes', + 'selfApply': 'No', + 'contracting': 'In Progress', + 'tender_submitted': '3', + 'approved_tenders': '2', + 'tender_value': '150000', + 'thunder_status': 'active', + 'your_tenders': [ + { + 'success': true, + 'message': 'Tender retrieved', + 'profile_match': 0.95, + 'data': { + 'id': 'tnd_001', + 'title': 'Bridge Construction Project', + 'country_code': 'US', + }, + 'error': null, + }, + ], + }; + + test('fromJson creates valid HomeResponseModel instance', () { + final response = HomeResponseModel.fromJson(mockJson); + + expect(response.partnership, 'Yes'); + expect(response.selfApply, 'No'); + expect(response.contracting, 'In Progress'); + expect(response.tenderSubmitted, '3'); + expect(response.approvedTenders, '2'); + expect(response.tenderValue, '150000'); + expect(response.thunderStatus, 'active'); + + final tender = response.yourTenders?.first; + expect(tender?.success, isTrue); + expect(tender?.message, 'Tender retrieved'); + expect(tender?.profileMatch, 0.95); + expect(tender?.data?.id, 'tnd_001'); + expect(tender?.data?.title, 'Bridge Construction Project'); + }); + + test('toJson converts model back to JSON correctly', () { + final response = HomeResponseModel.fromJson(mockJson); + final json = response.toJson(); + + expect(json['partnership'], 'Yes'); + expect(json['selfApply'], 'No'); + expect(json['tender_submitted'], '3'); + + final tenders = response.yourTenders ?? []; + expect(tenders.length, 1); + + final tender = tenders.first; + final tenderJson = tender.toJson(); + + expect(tenderJson['success'], true); + expect(tenderJson['message'], 'Tender retrieved'); + + final tenderData = + (tenderJson['data'] is Map) + ? tenderJson['data'] as Map + : tender.data?.toJson(); + + expect(tenderData?['id'], 'tnd_001'); + expect(tenderData?['title'], 'Bridge Construction Project'); + }); + + test('copyWith correctly updates fields', () { + final response = HomeResponseModel.fromJson(mockJson); + final updated = response.copyWith( + partnership: 'No', + tenderValue: '999999', + ); + + expect(updated.partnership, 'No'); + expect(updated.tenderValue, '999999'); + expect(updated.selfApply, equals('No')); + }); + + test('equality operator works correctly', () { + final res1 = HomeResponseModel.fromJson(mockJson); + final res2 = HomeResponseModel.fromJson(mockJson); + final res3 = res1.copyWith(partnership: 'Different'); + + expect(res1, equals(res2)); + expect(res1.hashCode, equals(res2.hashCode)); + expect(res1, isNot(equals(res3))); + }); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index f9f4717..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:tm_app/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}