JXDataModelTests.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. //
  2. // JXDataModelTests.m
  3. // AICityTests
  4. //
  5. // Feature: 010-ui-ios
  6. // 数据模型单元测试 - Phase 1数据模型
  7. //
  8. #import <XCTest/XCTest.h>
  9. #import "JXDramaContent.h"
  10. #import "JXCommentContent.h"
  11. #import "JXEpisodeInfo.h"
  12. @interface JXDataModelTests : XCTestCase
  13. @end
  14. @implementation JXDataModelTests
  15. #pragma mark - JXDramaContent 测试
  16. - (void)testJXDramaContentInitialization {
  17. // Given
  18. NSDictionary *dict = @{
  19. @"drama_id": @"D001",
  20. @"title": @"测试短剧",
  21. @"cover": @"https://example.com/cover.jpg",
  22. @"description": @"这是一部测试短剧",
  23. @"total_episodes": @10,
  24. @"category_id": @1,
  25. @"tags": @[@"爱情", @"都市"],
  26. @"release_date": @"2025-01-01",
  27. @"rating": @4.5,
  28. @"play_count": @100000,
  29. @"like_count": @5000,
  30. @"favorite_count": @2000,
  31. @"comment_count": @800,
  32. @"is_vip": @YES,
  33. @"file_id": @"FILE123",
  34. @"app_id": @"APP456",
  35. @"psign": @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6MTI1Mn0.test"
  36. };
  37. // When
  38. JXDramaContent *drama = [[JXDramaContent alloc] initWithDictionary:dict];
  39. // Then
  40. XCTAssertNotNil(drama);
  41. XCTAssertEqualObjects(drama.dramaId, @"D001");
  42. XCTAssertEqualObjects(drama.title, @"测试短剧");
  43. XCTAssertEqualObjects(drama.cover, @"https://example.com/cover.jpg");
  44. XCTAssertEqualObjects(drama.dramaDescription, @"这是一部测试短剧");
  45. XCTAssertEqual(drama.totalEpisodes, 10);
  46. XCTAssertEqual(drama.categoryId, 1);
  47. XCTAssertEqual(drama.tags.count, 2);
  48. XCTAssertEqual(drama.rating, 4.5);
  49. XCTAssertEqual(drama.playCount, 100000);
  50. XCTAssertEqual(drama.likeCount, 5000);
  51. XCTAssertEqual(drama.favoriteCount, 2000);
  52. XCTAssertEqual(drama.commentCount, 800);
  53. XCTAssertTrue(drama.isVIP);
  54. XCTAssertEqualObjects(drama.fileId, @"FILE123");
  55. XCTAssertEqualObjects(drama.appId, @"APP456");
  56. XCTAssertEqualObjects(drama.psign, @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJZCI6MTI1Mn0.test");
  57. }
  58. - (void)testJXDramaContentDefaultValues {
  59. // Given - 最小化字典
  60. NSDictionary *dict = @{
  61. @"drama_id": @"D002",
  62. @"title": @"简单短剧"
  63. };
  64. // When
  65. JXDramaContent *drama = [[JXDramaContent alloc] initWithDictionary:dict];
  66. // Then
  67. XCTAssertNotNil(drama);
  68. XCTAssertEqualObjects(drama.dramaId, @"D002");
  69. XCTAssertEqualObjects(drama.title, @"简单短剧");
  70. XCTAssertNil(drama.cover);
  71. XCTAssertNil(drama.dramaDescription);
  72. XCTAssertEqual(drama.totalEpisodes, 0);
  73. XCTAssertEqual(drama.playCount, 0);
  74. XCTAssertEqual(drama.likeCount, 0);
  75. XCTAssertFalse(drama.isVIP);
  76. }
  77. - (void)testJXDramaContentFormattedCounts {
  78. // Given
  79. NSDictionary *dict = @{
  80. @"drama_id": @"D003",
  81. @"title": @"热门短剧",
  82. @"play_count": @123456789,
  83. @"like_count": @5678,
  84. @"favorite_count": @12345,
  85. @"comment_count": @890
  86. };
  87. // When
  88. JXDramaContent *drama = [[JXDramaContent alloc] initWithDictionary:dict];
  89. // Then
  90. NSString *playCount = [drama formattedPlayCount];
  91. NSString *likeCount = [drama formattedLikeCount];
  92. NSString *favoriteCount = [drama formattedFavoriteCount];
  93. NSString *commentCount = [drama formattedCommentCount];
  94. XCTAssertNotNil(playCount);
  95. XCTAssertNotNil(likeCount);
  96. XCTAssertNotNil(favoriteCount);
  97. XCTAssertNotNil(commentCount);
  98. NSLog(@"播放量: %@", playCount);
  99. NSLog(@"点赞数: %@", likeCount);
  100. NSLog(@"收藏数: %@", favoriteCount);
  101. NSLog(@"评论数: %@", commentCount);
  102. }
  103. - (void)testJXDramaContentIsLikedAndFavorited {
  104. // Given
  105. NSDictionary *dict = @{
  106. @"drama_id": @"D004",
  107. @"title": @"已点赞收藏",
  108. @"is_liked": @YES,
  109. @"is_favorited": @YES
  110. };
  111. // When
  112. JXDramaContent *drama = [[JXDramaContent alloc] initWithDictionary:dict];
  113. // Then
  114. XCTAssertTrue(drama.isLiked);
  115. XCTAssertTrue(drama.isFavorited);
  116. }
  117. #pragma mark - JXCommentContent 测试
  118. - (void)testJXCommentContentInitialization {
  119. // Given
  120. NSDictionary *dict = @{
  121. @"comment_id": @123456,
  122. @"user_id": @789,
  123. @"user_name": @"测试用户",
  124. @"user_avatar": @"https://example.com/avatar.jpg",
  125. @"content": @"这部剧太好看了!",
  126. @"like_count": @50,
  127. @"reply_count": @10,
  128. @"created_at": @1698000000000LL, // 毫秒时间戳
  129. @"is_liked": @YES,
  130. @"is_author": @NO
  131. };
  132. // When
  133. JXCommentContent *comment = [[JXCommentContent alloc] initWithDictionary:dict];
  134. // Then
  135. XCTAssertNotNil(comment);
  136. XCTAssertEqual(comment.commentId, 123456);
  137. XCTAssertEqual(comment.userId, 789);
  138. XCTAssertEqualObjects(comment.userName, @"测试用户");
  139. XCTAssertEqualObjects(comment.userAvatar, @"https://example.com/avatar.jpg");
  140. XCTAssertEqualObjects(comment.content, @"这部剧太好看了!");
  141. XCTAssertEqual(comment.likeCount, 50);
  142. XCTAssertEqual(comment.replyCount, 10);
  143. XCTAssertEqual(comment.createdAt, 1698000000000LL);
  144. XCTAssertTrue(comment.isLiked);
  145. XCTAssertFalse(comment.isAuthor);
  146. }
  147. - (void)testJXCommentContentFormattedTime {
  148. // Given - 今年内的评论
  149. NSDate *now = [NSDate date];
  150. NSCalendar *calendar = [NSCalendar currentCalendar];
  151. NSInteger currentYear = [calendar component:NSCalendarUnitYear fromDate:now];
  152. NSDateComponents *components = [[NSDateComponents alloc] init];
  153. components.year = currentYear;
  154. components.month = 6;
  155. components.day = 15;
  156. NSDate *thisYear = [calendar dateFromComponents:components];
  157. int64_t thisYearTimestamp = (int64_t)([thisYear timeIntervalSince1970] * 1000);
  158. NSDictionary *dict1 = @{
  159. @"comment_id": @1,
  160. @"content": @"今年的评论",
  161. @"created_at": @(thisYearTimestamp)
  162. };
  163. // Given - 非今年的评论
  164. components.year = currentYear - 1;
  165. NSDate *lastYear = [calendar dateFromComponents:components];
  166. int64_t lastYearTimestamp = (int64_t)([lastYear timeIntervalSince1970] * 1000);
  167. NSDictionary *dict2 = @{
  168. @"comment_id": @2,
  169. @"content": @"去年的评论",
  170. @"created_at": @(lastYearTimestamp)
  171. };
  172. // When
  173. JXCommentContent *comment1 = [[JXCommentContent alloc] initWithDictionary:dict1];
  174. JXCommentContent *comment2 = [[JXCommentContent alloc] initWithDictionary:dict2];
  175. // Then
  176. NSString *time1 = [comment1 formattedTime];
  177. NSString *time2 = [comment2 formattedTime];
  178. XCTAssertNotNil(time1);
  179. XCTAssertNotNil(time2);
  180. // 今年的应该是 MM-dd 格式
  181. XCTAssertTrue([time1 rangeOfString:@"-"].location != NSNotFound);
  182. XCTAssertFalse([time1 hasPrefix:[NSString stringWithFormat:@"%ld", (long)currentYear]]);
  183. // 去年的应该是 yyyy-MM-dd 格式
  184. XCTAssertTrue([time2 hasPrefix:[NSString stringWithFormat:@"%ld", (long)(currentYear - 1)]]);
  185. NSLog(@"今年评论时间: %@", time1);
  186. NSLog(@"去年评论时间: %@", time2);
  187. }
  188. - (void)testJXCommentContentFormattedCounts {
  189. // Given
  190. NSDictionary *dict = @{
  191. @"comment_id": @1,
  192. @"content": @"热门评论",
  193. @"like_count": @12345,
  194. @"reply_count": @678
  195. };
  196. // When
  197. JXCommentContent *comment = [[JXCommentContent alloc] initWithDictionary:dict];
  198. // Then
  199. NSString *likeCount = [comment formattedLikeCount];
  200. NSString *replyCount = [comment formattedReplyCount];
  201. XCTAssertNotNil(likeCount);
  202. XCTAssertNotNil(replyCount);
  203. NSLog(@"点赞数: %@", likeCount);
  204. NSLog(@"回复数: %@", replyCount);
  205. }
  206. #pragma mark - JXEpisodeInfo 测试
  207. - (void)testJXEpisodeInfoInitialization {
  208. // Given
  209. NSDictionary *dict = @{
  210. @"episode_id": @"EP001",
  211. @"episode_number": @5,
  212. @"title": @"第5集",
  213. @"cover": @"https://example.com/ep5.jpg",
  214. @"duration": @600,
  215. @"is_vip": @YES,
  216. @"file_id": @"FILE789",
  217. @"app_id": @"APP101",
  218. @"psign": @"test_psign"
  219. };
  220. // When
  221. JXEpisodeInfo *episode = [[JXEpisodeInfo alloc] initWithDictionary:dict];
  222. // Then
  223. XCTAssertNotNil(episode);
  224. XCTAssertEqualObjects(episode.episodeId, @"EP001");
  225. XCTAssertEqual(episode.episodeNumber, 5);
  226. XCTAssertEqualObjects(episode.title, @"第5集");
  227. XCTAssertEqualObjects(episode.cover, @"https://example.com/ep5.jpg");
  228. XCTAssertEqual(episode.duration, 600);
  229. XCTAssertTrue(episode.isVIP);
  230. XCTAssertEqualObjects(episode.fileId, @"FILE789");
  231. XCTAssertEqualObjects(episode.appId, @"APP101");
  232. XCTAssertEqualObjects(episode.psign, @"test_psign");
  233. }
  234. - (void)testJXEpisodeInfoFormattedDuration {
  235. // Given
  236. NSDictionary *dict1 = @{
  237. @"episode_id": @"EP001",
  238. @"duration": @65 // 1分05秒
  239. };
  240. NSDictionary *dict2 = @{
  241. @"episode_id": @"EP002",
  242. @"duration": @3665 // 1小时1分05秒
  243. };
  244. NSDictionary *dict3 = @{
  245. @"episode_id": @"EP003",
  246. @"duration": @600 // 10分钟
  247. };
  248. // When
  249. JXEpisodeInfo *episode1 = [[JXEpisodeInfo alloc] initWithDictionary:dict1];
  250. JXEpisodeInfo *episode2 = [[JXEpisodeInfo alloc] initWithDictionary:dict2];
  251. JXEpisodeInfo *episode3 = [[JXEpisodeInfo alloc] initWithDictionary:dict3];
  252. // Then
  253. NSString *duration1 = [episode1 formattedDuration];
  254. NSString *duration2 = [episode2 formattedDuration];
  255. NSString *duration3 = [episode3 formattedDuration];
  256. XCTAssertEqualObjects(duration1, @"01:05");
  257. XCTAssertEqualObjects(duration2, @"61:05");
  258. XCTAssertEqualObjects(duration3, @"10:00");
  259. NSLog(@"时长1: %@", duration1);
  260. NSLog(@"时长2: %@", duration2);
  261. NSLog(@"时长3: %@", duration3);
  262. }
  263. #pragma mark - 边界值测试
  264. - (void)testNilDictionaryHandling {
  265. // When
  266. JXDramaContent *drama = [[JXDramaContent alloc] initWithDictionary:nil];
  267. JXCommentContent *comment = [[JXCommentContent alloc] initWithDictionary:nil];
  268. JXEpisodeInfo *episode = [[JXEpisodeInfo alloc] initWithDictionary:nil];
  269. // Then - 应该优雅处理nil,不崩溃
  270. XCTAssertNotNil(drama);
  271. XCTAssertNotNil(comment);
  272. XCTAssertNotNil(episode);
  273. }
  274. - (void)testEmptyDictionaryHandling {
  275. // When
  276. JXDramaContent *drama = [[JXDramaContent alloc] initWithDictionary:@{}];
  277. JXCommentContent *comment = [[JXCommentContent alloc] initWithDictionary:@{}];
  278. JXEpisodeInfo *episode = [[JXEpisodeInfo alloc] initWithDictionary:@{}];
  279. // Then - 应该优雅处理空字典
  280. XCTAssertNotNil(drama);
  281. XCTAssertNotNil(comment);
  282. XCTAssertNotNil(episode);
  283. }
  284. - (void)testInvalidDataTypeHandling {
  285. // Given - 错误的数据类型
  286. NSDictionary *dict = @{
  287. @"drama_id": @123, // 应该是字符串
  288. @"title": @456, // 应该是字符串
  289. @"total_episodes": @"abc", // 应该是数字
  290. @"is_vip": @"yes" // 应该是布尔值
  291. };
  292. // When
  293. JXDramaContent *drama = [[JXDramaContent alloc] initWithDictionary:dict];
  294. // Then - 应该优雅处理类型转换
  295. XCTAssertNotNil(drama);
  296. }
  297. #pragma mark - 性能测试
  298. - (void)testPerformanceJXDramaContentInitialization {
  299. NSDictionary *dict = @{
  300. @"drama_id": @"D999",
  301. @"title": @"性能测试短剧",
  302. @"play_count": @100000,
  303. @"like_count": @5000
  304. };
  305. [self measureBlock:^{
  306. for (int i = 0; i < 1000; i++) {
  307. JXDramaContent *drama = [[JXDramaContent alloc] initWithDictionary:dict];
  308. (void)drama;
  309. }
  310. }];
  311. }
  312. - (void)testPerformanceJXCommentContentInitialization {
  313. NSDictionary *dict = @{
  314. @"comment_id": @123,
  315. @"content": @"性能测试评论",
  316. @"created_at": @1698000000000LL
  317. };
  318. [self measureBlock:^{
  319. for (int i = 0; i < 1000; i++) {
  320. JXCommentContent *comment = [[JXCommentContent alloc] initWithDictionary:dict];
  321. (void)comment;
  322. }
  323. }];
  324. }
  325. @end