ViewController.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. //
  2. // ViewController.swift
  3. // KdanAuto
  4. //
  5. // Created by 朱东勇 on 2022/11/17.
  6. //
  7. import Cocoa
  8. import ComPDFKit_Conversion
  9. class ViewController : NSViewController, SettingViewControllerDelegate, AutoTestAdvanceSettingViewDelegate, TestCaseCellViewDelegate,
  10. NSTableViewDelegate, NSTableViewDataSource {
  11. @IBOutlet var customView : NSView!
  12. @IBOutlet var settingVCWindow : NSWindow!
  13. @IBOutlet var settingVC : SettingViewController!
  14. @IBOutlet var itemsList : NSTableView!
  15. var _currentCellInfo : AutoTestCellInfo?
  16. @IBOutlet var advanceView : AutoTestAdvanceSettingView!
  17. @IBOutlet var startBtn : NSButton!
  18. @IBOutlet var replaceAllBtn : NSButton!
  19. @IBOutlet var exportReportBtn : NSButton!
  20. @IBOutlet var advanceBtn : NSButton!
  21. @IBOutlet var latestResultBtn : NSButton!
  22. var operateQueue = OperationQueue()
  23. var _isProcessing : Bool!
  24. var autotestBlock:(NSMutableArray) -> () = { (objects:NSMutableArray) in
  25. };
  26. var _selectFileType : String! = ""
  27. override func viewDidLoad() {
  28. super.viewDidLoad()
  29. customView.wantsLayer = true;
  30. customView.layer?.borderColor = NSColor.lightGray.withAlphaComponent(0.4).cgColor
  31. customView.layer?.borderWidth = 1
  32. advanceView.wantsLayer = true
  33. advanceView.layer?.borderColor = NSColor.lightGray.withAlphaComponent(0.4).cgColor
  34. advanceView.layer?.borderWidth = 1
  35. // Load Infos
  36. var path = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first?.appending("/CustomAutoTestProperty.plist")
  37. if nil == path || !FileManager.default.fileExists(atPath: path!) {
  38. path = Bundle.main.path(forResource: "AutoTestProperty", ofType: "plist")!
  39. }
  40. let url = URL.init(fileURLWithPath: path!, isDirectory: false)
  41. let initInfo = try! NSDictionary.init(contentsOf: url, error: ())
  42. testFileTypes = initInfo.allKeys as [String]
  43. testTypeInfo = initInfo as NSDictionary
  44. //
  45. advanceView.delegate = self;
  46. updateProcessStatus()
  47. self.replaceAllBtn.isEnabled = false;
  48. self.exportReportBtn.isEnabled = false;
  49. DispatchQueue.global().async {
  50. for fileType in testFileTypes {
  51. let types = testTypeInfo[fileType] as! NSArray
  52. for typeInfo in types {
  53. let ti = typeInfo as! NSDictionary
  54. let id = ti["ID"] as! NSString
  55. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  56. if testObject != nil &&
  57. testObject!.canUpdateRefImage() {
  58. DispatchQueue.main.sync {
  59. self.replaceAllBtn.isEnabled = true;
  60. }
  61. break
  62. }
  63. }
  64. }
  65. }
  66. DispatchQueue.main.async {
  67. self.view.window?.title = "KdanAuto:"+CPDFConvertKit.sharedInstance().versionString
  68. }
  69. }
  70. override func awakeFromNib() {
  71. super.awakeFromNib()
  72. NotificationCenter.default.addObserver(forName: NSNotification.Name(kAutoTestObjectUpdateNotification),
  73. object: nil,
  74. queue: nil) { notifiication in
  75. self.itemsList.reloadData()
  76. }
  77. }
  78. override func viewWillAppear() {
  79. super.viewWillAppear()
  80. self.view.window?.orderFront(nil)
  81. }
  82. override var representedObject: Any? {
  83. didSet {
  84. // Update the view, if already loaded.
  85. }
  86. }
  87. func reloadListData() {
  88. itemsList.reloadData()
  89. }
  90. // Update
  91. func updateProcessStatus() {
  92. startBtn.wantsLayer = true;
  93. startBtn.layer?.cornerRadius = startBtn.frame.width / 2.0
  94. startBtn.layer?.backgroundColor = NSColor.init(red: 0, green: 0.6, blue: 0.6, alpha: 1).cgColor;
  95. startBtn.contentTintColor = NSColor.white
  96. }
  97. // Setter & Getter
  98. func setCurrentCellInfo(_ cellInfo : AutoTestCellInfo?) {
  99. _currentCellInfo = cellInfo
  100. if (nil != _currentCellInfo) {
  101. let autoTestObj = AutoTest.autoTestFor(NSString(string: (_currentCellInfo?.fileType())!), id:NSString(string: (_currentCellInfo?.typeInfo()["ID"] as! String)))
  102. advanceView.setAutoTestObj(autoTestObj)
  103. }else {
  104. advanceView.setAutoTestObj(nil)
  105. }
  106. }
  107. // IBAction
  108. @IBAction func showSettingVC(_ sender:NSButton) {
  109. let settingVC = SettingViewController.shared()
  110. settingVC.delegate = self
  111. settingVC.show()
  112. }
  113. @IBAction func startAction(_ sender:NSButton) {
  114. let path = DataModel.shared.directoryPath();
  115. if NSString(string: path).isEqual(to: "") || !FileManager.default.fileExists(atPath: path) {
  116. return
  117. }
  118. _isProcessing = true;
  119. updateProcessStatus()
  120. startBtn.isEnabled = false
  121. startBtn.title = "Doing"
  122. exportReportBtn.isEnabled = false;
  123. replaceAllBtn.isEnabled = false;
  124. advanceBtn.isEnabled = false;
  125. DispatchQueue.global().async {
  126. let report = NSMutableAttributedString.init(string: "");
  127. DataModel.shared.generaNewReportID()
  128. TestDegreeManager.shared().clearAllHistory()
  129. let objects = NSMutableArray()
  130. // Update For Waiting
  131. for fileType in testFileTypes {
  132. let types = testTypeInfo[fileType] as! NSArray
  133. for typeInfo in types {
  134. let ti = typeInfo as! NSDictionary
  135. let id = ti["ID"] as! NSString
  136. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  137. testObject?.testlog = { (msg, progress) in
  138. DispatchQueue.main.async {
  139. self.view.window?.title = "\(msg)(\(Int(progress*100))%)";
  140. if (testObject!.isEqual(to: self.advanceView._autoTestObj)) {
  141. self.advanceView.setAutoTestObj(testObject)
  142. }
  143. }
  144. }
  145. if (testObject != nil &&
  146. testObject!.needCompareTest()) {
  147. objects.add(testObject!);
  148. testObject?.setStatus(.Wait)
  149. }
  150. }
  151. DispatchQueue.main.sync {
  152. self.reloadListData()
  153. }
  154. }
  155. var objectIndex = 0
  156. //创建 Block
  157. self.autotestBlock = { (objects:NSMutableArray) in
  158. NSLog("[KdanAuto]Auto Test \(objectIndex)")
  159. if (objectIndex >= objects.count) {
  160. // 所有自动化测试对象均执行完成
  161. do {
  162. let rtfData = try? report.data(from: .init(location: 0, length: report.length),
  163. documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf])
  164. let path = NSString(string: DataModel.shared.directoryPath()).appendingPathComponent("TestReport_\(DataModel.shared.latestReportID() ?? "").rtf")
  165. try? FileManager.default.removeItem(atPath: path);
  166. try? rtfData?.write(to: NSURL.fileURL(withPath: path))
  167. } catch {
  168. }
  169. DispatchQueue.main.async {
  170. self.view.window?.title = "KdanAuto:"+CPDFConvertKit.sharedInstance().versionString
  171. self._isProcessing = false
  172. self.updateProcessStatus()
  173. self.startBtn.isEnabled = true
  174. self.startBtn.title = "Start"
  175. self.replaceAllBtn.isEnabled = true
  176. self.exportReportBtn.isEnabled = true;
  177. self.advanceBtn.isEnabled = true;
  178. TestDegreeManager.shared().saveInfo()
  179. }
  180. return
  181. }
  182. // 执行当前索引自动化测试对象
  183. let testobject = objects.object(at: objectIndex) as! AutoTest
  184. testobject.setStatus(.Process)
  185. // 异步执行自动化测试
  186. var complention:(_ object:AutoTest, _ report:NSAttributedString?) -> () = {(object, inReport) in
  187. };
  188. complention = {(object, inReport) in
  189. if inReport != nil {
  190. // 如果有自动化测试报告,则拼接在后面
  191. report.append(inReport!)
  192. }
  193. if (Thread.isMainThread) {
  194. // 更新当前自动化测试对象状态及相关 UI 状态
  195. object.setStatus(.Finished)
  196. self.reloadListData()
  197. if (self.advanceView.getAutoTestObj() != nil &&
  198. object.isEqual(to: self.advanceView.getAutoTestObj())) {
  199. self.advanceView.setAutoTestObj(self.advanceView.getAutoTestObj());
  200. }
  201. }else {
  202. DispatchQueue.main.sync {
  203. // 更新当前自动化测试对象状态及相关 UI 状态
  204. object.setStatus(.Finished)
  205. self.reloadListData()
  206. if (self.advanceView.getAutoTestObj() != nil &&
  207. object.isEqual(to: self.advanceView.getAutoTestObj())) {
  208. self.advanceView.setAutoTestObj(self.advanceView.getAutoTestObj());
  209. }
  210. }
  211. }
  212. DispatchQueue.global().asyncAfter(deadline: DispatchTime.init(uptimeNanoseconds: 300)) {
  213. autoreleasepool {
  214. // 触发下一个自动化测试对象进入自动化测试
  215. objectIndex += 1
  216. self.autotestBlock(objects)
  217. }
  218. }
  219. };
  220. testobject.autoTest(complention);
  221. }
  222. // 异步第0号位置自动化测试
  223. self.autotestBlock(objects)
  224. }
  225. }
  226. @IBAction func relpaceAllAction(_ sender:NSButton) {
  227. // Replace all refrence images for all type
  228. self.startBtn.isEnabled = false
  229. self.replaceAllBtn.isEnabled = false
  230. DispatchQueue.global().async {
  231. // Update For Waiting
  232. for fileType in testFileTypes {
  233. let types = testTypeInfo[fileType] as! NSArray
  234. for typeInfo in types {
  235. autoreleasepool {
  236. let ti = typeInfo as! NSDictionary
  237. let id = ti["ID"] as! NSString
  238. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  239. testObject?.updateRefImage()
  240. }
  241. }
  242. DispatchQueue.main.sync {
  243. self.reloadListData()
  244. }
  245. }
  246. DispatchQueue.main.async {
  247. self.startBtn.isEnabled = true
  248. self.advanceView.setAutoTestObj(self.advanceView._autoTestObj)
  249. }
  250. }
  251. }
  252. @IBAction func selectAllTestItem(_ sender:NSButton) {
  253. for fileType in testFileTypes {
  254. let types = testTypeInfo[fileType] as! NSArray
  255. for typeInfo in types {
  256. let ti = typeInfo as! NSDictionary
  257. let id = ti["ID"] as! NSString
  258. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  259. if nil != testObject {
  260. testObject?.setSelectedKeys((testObject?.keys())!)
  261. }
  262. }
  263. self.reloadListData()
  264. advanceView.setAutoTestObj(advanceView._autoTestObj)
  265. }
  266. }
  267. @IBAction func clearAllCheckFilesItem(_ sender:NSButton) {
  268. DispatchQueue.global().async {
  269. autoreleasepool {
  270. for fileType in testFileTypes {
  271. let types = testTypeInfo[fileType] as! NSArray
  272. for typeInfo in types {
  273. let ti = typeInfo as! NSDictionary
  274. let id = ti["ID"] as! NSString
  275. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  276. if nil != testObject {
  277. testObject?.clearCompareFiles()
  278. }
  279. }
  280. }
  281. DispatchQueue.main.async {
  282. autoreleasepool {
  283. self.reloadListData()
  284. self.advanceView.setAutoTestObj(self.advanceView._autoTestObj)
  285. }
  286. }
  287. }
  288. }
  289. }
  290. @IBAction func clearAllReportItem(_ sender:NSButton) {
  291. DispatchQueue.global().async {
  292. autoreleasepool {
  293. for fileType in testFileTypes {
  294. let types = testTypeInfo[fileType] as! NSArray
  295. for typeInfo in types {
  296. let ti = typeInfo as! NSDictionary
  297. let id = ti["ID"] as! NSString
  298. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  299. if nil != testObject {
  300. testObject?.clearCacheFiles()
  301. }
  302. }
  303. }
  304. DispatchQueue.main.async {
  305. autoreleasepool {
  306. self.reloadListData()
  307. self.advanceView.setAutoTestObj(self.advanceView._autoTestObj)
  308. }
  309. }
  310. }
  311. }
  312. }
  313. @IBAction func diselectAllTestItem(_ sender:NSButton) {
  314. for fileType in testFileTypes {
  315. let types = testTypeInfo[fileType] as! NSArray
  316. for typeInfo in types {
  317. let ti = typeInfo as! NSDictionary
  318. let id = ti["ID"] as! NSString
  319. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  320. if nil != testObject {
  321. testObject?.setSelectedKeys([])
  322. }
  323. }
  324. self.reloadListData()
  325. advanceView.setAutoTestObj(advanceView._autoTestObj)
  326. }
  327. }
  328. @IBAction func showCompareReportAction(_ sender:NSButton) {
  329. let files = NSMutableArray()
  330. for fileType in testFileTypes {
  331. let types = testTypeInfo[fileType] as! NSArray
  332. for typeInfo in types {
  333. let ti = typeInfo as! NSDictionary
  334. let id = ti["ID"] as! NSString
  335. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  336. if (testObject?.selectedKeys().count != 0) {
  337. let tFiles = testObject?.compareFiles();
  338. if (tFiles != nil && tFiles?.count != 0) {
  339. files.addObjects(from: tFiles as! [Any])
  340. }
  341. }
  342. }
  343. }
  344. if files.count > 0 {
  345. let compareVC = CompareViewController.shared()
  346. compareVC.setFiles(files)
  347. let point = sender.convert(CGPoint(x: 0, y: 0), to: self.view.window?.contentView ?? self.view)
  348. compareVC.showIn(self.view.window?.contentView ?? self.view, rect: NSRect.init(origin: point, size: sender.frame.size))
  349. }
  350. return
  351. }
  352. @IBAction func showLatestReportAction(_ sender:NSButton) {
  353. latestResultBtn.isHidden = true;
  354. for fileType in testFileTypes {
  355. let types = testTypeInfo[fileType] as! NSArray
  356. for typeInfo in types {
  357. let ti = typeInfo as! NSDictionary
  358. let id = ti["ID"] as! NSString
  359. let testObject = AutoTest.autoTestFor(fileType as NSString, id: id)
  360. if (testObject?.selectedKeys().count ?? 0 > 0) {
  361. testObject?.setStatus(.Finished)
  362. }
  363. }
  364. }
  365. self.reloadListData()
  366. }
  367. // TableView Delegate
  368. func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
  369. let cellInfo = AutoTestCellInfo.initWithRow(row)
  370. if cellInfo.isFileType() {
  371. let cellView = TestFileTypeCellView.shared()
  372. let title = cellInfo.fileType()
  373. cellView?.setTitle(title)
  374. return cellView
  375. }else {
  376. let cellView = TestCaseCellView.shared()
  377. let autoTestObj = AutoTest.autoTestFor(NSString(string: (cellInfo.fileType())), id:NSString(string: (cellInfo.typeInfo()["ID"] as! String)))
  378. cellView?.setAutoTestObj(autoTestObj);
  379. cellView?.delegate = self;
  380. return cellView
  381. }
  382. }
  383. func selectionShouldChange(in tableView: NSTableView) -> Bool {
  384. return true
  385. }
  386. func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
  387. return true
  388. }
  389. func tableView(_ tableView: NSTableView, shouldSelect tableColumn: NSTableColumn?) -> Bool {
  390. return false
  391. }
  392. func tableView(_ tableView: NSTableView, mouseDownInHeaderOf tableColumn: NSTableColumn) {
  393. }
  394. func tableView(_ tableView: NSTableView, didClick tableColumn: NSTableColumn) {
  395. }
  396. func tableView(_ tableView: NSTableView, didDrag tableColumn: NSTableColumn) {
  397. }
  398. func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
  399. let cellInfo = AutoTestCellInfo.initWithRow(row)
  400. if cellInfo.isFileType() {
  401. return 30
  402. }else {
  403. return 60
  404. }
  405. }
  406. func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
  407. return false
  408. }
  409. func tableView(_ tableView: NSTableView, sizeToFitWidthOfColumn column: Int) -> CGFloat {
  410. return tableView.frame.width
  411. }
  412. func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge: NSTableView.RowActionEdge) -> [NSTableViewRowAction] {
  413. return []
  414. }
  415. func tableViewSelectionDidChange(_ notification: Notification) {
  416. if ((notification.object as! NSTableView) == itemsList) {
  417. let selectRow = itemsList.selectedRow
  418. if selectRow != -1 {
  419. let cellInfo = AutoTestCellInfo.initWithRow(selectRow)
  420. if cellInfo.isFileType() {
  421. let isExpend = DataModel.shared.isExpand(cellInfo.fileType())
  422. DataModel.shared.setIsExpand(cellInfo.fileType(), expand: (!isExpend))
  423. itemsList.reloadData()
  424. }else {
  425. self.setCurrentCellInfo(cellInfo)
  426. }
  427. }else {
  428. }
  429. }
  430. }
  431. // TableView Data Source
  432. func numberOfRows(in tableView: NSTableView) -> Int {
  433. var count = testFileTypes.count
  434. for fileType in testFileTypes {
  435. //当前文件类型是否为展开
  436. if (DataModel.shared.isExpand(fileType)) {
  437. let testTypes = testTypeInfo[fileType] as! NSArray
  438. count = count + testTypes.count
  439. }
  440. }
  441. return count
  442. }
  443. /* This method is required for the "Cell Based" TableView, and is optional for the "View Based" TableView. If implemented in the latter case, the value will be set to the view at a given row/column if the view responds to -setObjectValue: (such as NSControl and NSTableCellView). Note that NSTableCellView does not actually display the objectValue, and its value is to be used for bindings. See NSTableCellView.h for more information.
  444. */
  445. // func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
  446. // return testCaseNames[row]
  447. // }
  448. // SettingViewConntroller Handle
  449. func settingViewDidFinished() {
  450. reloadListData()
  451. }
  452. //AutoTestAdvanceSettingView Delegate
  453. func advanceSettingDidUpdate(_ settingView: NSView?) {
  454. if (nil != _currentCellInfo) {
  455. itemsList.reloadData(forRowIndexes: IndexSet(integer: IndexSet.Element((_currentCellInfo?._row)!)),
  456. columnIndexes: IndexSet(integer: IndexSet.Element(0)))
  457. }else {
  458. reloadListData()
  459. }
  460. }
  461. //TestCaseCellViewDelegate
  462. func selectKeyDidUpdate(_ cell: NSTableCellView?) {
  463. advanceView._autoTestObj = advanceView._autoTestObj
  464. }
  465. }