ViewController.swift 23 KB

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