ViewController.swift 22 KB

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