AutoTest.swift 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. //
  2. // AutoTest.swift
  3. // KdanAuto
  4. //
  5. // Created by 朱东勇 on 2022/11/25.
  6. //
  7. import Foundation
  8. import AppKit
  9. var cacheObjects = NSMutableDictionary()
  10. let operateQueue = OperationQueue()
  11. class AutoTest : NSObject, AutoTestProtocal {
  12. var reportString : NSMutableAttributedString? = nil
  13. public var _status : AutoTestStatus = .Normal
  14. var m_info:NSDictionary!
  15. var _fileType : String = "RTF"
  16. var m_id : String = ""
  17. var _type : String = "Others"
  18. var _extention : String = "rtf"
  19. var _name : String = "对照测试"
  20. var _params : NSDictionary = [:]
  21. var testFiles : NSArray = NSArray()
  22. var convertFiles : NSMutableArray = NSMutableArray()
  23. var convertProgress : Double = 0.0
  24. var compareFinishedFiles : NSMutableArray = NSMutableArray()
  25. var compareProgress : Double = 0.0
  26. var testlog : (_ msg:String, _ progress:Double) -> () = {(msg, progress) in
  27. }
  28. class func autoTestFor(_ fileType:NSString ,id:NSString) -> AutoTest? {
  29. let key = String(fileType)
  30. let ID = String(id)
  31. if cacheObjects.value(forKey: key) != nil {
  32. let objectInfo = cacheObjects.value(forKey: key) as! NSMutableDictionary
  33. if objectInfo.value(forKey: ID) != nil {
  34. let object = objectInfo.value(forKey: ID)
  35. return object as? AutoTest
  36. }
  37. }
  38. let fileTypes = testTypeInfo[fileType] as! NSArray
  39. let clsname = "KdanAuto"//Bundle.main.infoDictionary! ["CFBundleExecutable"]
  40. var objectInfo = cacheObjects.value(forKey: key) as? NSMutableDictionary
  41. if (nil == objectInfo) {
  42. objectInfo = NSMutableDictionary()
  43. cacheObjects.setValue(objectInfo, forKey: key)
  44. }
  45. for item in fileTypes {
  46. let cItem = item as! NSDictionary
  47. let cID = cItem["ID"] as! NSString
  48. let cType = cItem["Type"] as! NSString
  49. let cExtention = cItem["Extention"] as! NSString
  50. let cName = cItem["Name"] as! NSString
  51. let cParams = cItem["Params"] as? NSDictionary
  52. if (cID.isEqual(to: ID)) {
  53. let className = String((clsname )+"."+(cItem["Class"] as! String))
  54. let cl = NSClassFromString(className) as! AutoTest.Type
  55. let object = cl.shared()
  56. object?.m_id = cID as String
  57. object?.m_info = cItem
  58. object?._fileType = fileType as String
  59. object?._type = String(cType)
  60. object?._extention = String(cExtention)
  61. object?._name = String(cName)
  62. if nil != cParams {
  63. object?._params = cParams ?? [:];
  64. }
  65. objectInfo!.setValue(object, forKey: ID)
  66. return object
  67. }
  68. }
  69. let object = AutoTest.shared()
  70. object?.m_id = id as String
  71. object?._fileType = fileType as String
  72. object?._type = String(cType)
  73. object?._extention = ""
  74. object?._name = "对照测试"
  75. objectInfo!.setValue(object, forKey: ID)
  76. return object
  77. }
  78. class func shared() -> AutoTest? {
  79. return AutoTest()
  80. }
  81. func fileType() -> String {
  82. return _fileType
  83. }
  84. func type() -> String {
  85. return _type
  86. }
  87. func name() -> String {
  88. return _name
  89. }
  90. func extention() -> String {
  91. return _extention
  92. }
  93. func params() -> NSDictionary {
  94. return _params
  95. }
  96. func keys() -> NSArray {
  97. return ["快照"]
  98. }
  99. func selectedKeys() -> NSArray {
  100. let userDefaults = UserDefaults.standard
  101. let key = self.fileType() + "." + self.type() + ".selectedKeys"
  102. if userDefaults.value(forKey: key) != nil {
  103. return userDefaults.value(forKey: key) as! NSArray
  104. }
  105. self.setSelectedKeys(self.keys())
  106. return self.keys()
  107. }
  108. func setSelectedKeys(_ keys: NSArray) {
  109. let userDefaults = UserDefaults.standard
  110. let key = self.fileType() + "." + self.type() + ".selectedKeys"
  111. userDefaults.setValue(keys, forKey: key)
  112. userDefaults.synchronize()
  113. }
  114. func needCompareTest() -> Bool {
  115. return self.selectedKeys().contains("快照")
  116. }
  117. func status() -> AutoTestStatus {
  118. return _status
  119. }
  120. func setStatus(_ status:AutoTestStatus) {
  121. _status = status
  122. }
  123. // Auto Test
  124. func autoTest(_ complention:@escaping (_ object:AutoTest, _ report:NSAttributedString?) -> ()) {
  125. self.compareFinishedFiles.removeAllObjects();
  126. self.convertFiles.removeAllObjects()
  127. NSLog(String("转换\(self.type())"))
  128. let needCompare = self.selectedKeys().contains("快照")
  129. if !needCompare {
  130. // 未勾选 ”快照“ 选项
  131. self._status = .Finished
  132. complention(self, self.reportString)
  133. return
  134. }
  135. clearCacheFiles()
  136. if hasOriginFile() {
  137. //目录中有需要执行对照的文件
  138. DispatchQueue.global().async {
  139. autoreleasepool {
  140. self._status = .Process
  141. self.reportString = NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】快照比对开始!\n",
  142. attributes:[.foregroundColor : NSColor.blue])
  143. let files = DataModel.shared.originFilesFor(self.fileType(), type: self.type()) as [String]
  144. self.testFiles = NSArray(array: files);
  145. let checkDirectory = self.checkFileDirectory()
  146. let originDirectory = self.originFileDirectory()
  147. let resultDirectory = self.resultFileDirectory()
  148. if (files.count > 0) {
  149. try? FileManager.default.createDirectory(atPath: checkDirectory, withIntermediateDirectories: true);
  150. try? FileManager.default.createDirectory(atPath: resultDirectory, withIntermediateDirectories: true);
  151. }
  152. var tDegree = Double(0);
  153. var tCount = Int(0)
  154. var fileIndex = 0
  155. var compareIndex = 0;
  156. var convertFinished = false;
  157. // 用 Block 递归调用形式,确保转档单任务执行
  158. var convertFileBlock = { (files:[String]) in }
  159. convertFileBlock = { (files:[String]) in
  160. if (fileIndex >= files.count) {
  161. convertFinished = true;
  162. return
  163. }
  164. //
  165. let fileName = files[fileIndex];
  166. autoreleasepool {
  167. let checkDirectory = self.checkFileDirectory()
  168. let originDirectory = self.originFileDirectory()
  169. let resultDirectory = self.resultFileDirectory()
  170. let fName = NSString(string: fileName).deletingPathExtension
  171. let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
  172. let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+self.extention())
  173. // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention)
  174. // self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】开始转换文件 \"\(fName)\"\n",
  175. // attributes:[.foregroundColor : NSColor.blue]))
  176. // ...
  177. // 执行异步转换过程
  178. let index = self.testFiles.index(of: fileName);
  179. if (index != NSNotFound) {
  180. self.convertProgress = Double(index) / Double(self.testFiles.count)
  181. }
  182. self.convertFiles.add(fileName);
  183. self.testlog("开始转换:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
  184. self.process(originPath, resultPath: resultPath) { status in
  185. DispatchQueue.global().async {
  186. Thread.sleep(forTimeInterval: 0.3)
  187. fileIndex += 1;
  188. convertFileBlock(files)
  189. self.compareResult(fileName, resultPath: resultPath, status: status, needCompare: needCompare) { degree in
  190. autoreleasepool {
  191. if (degree >= 0.0) {
  192. tDegree += degree;
  193. tCount += 1;
  194. }
  195. compareIndex += 1;
  196. if (convertFinished && compareIndex >= files.count) {
  197. //所有任务已经执行完成
  198. TestDegreeManager.shared().set(((tCount != 0) ? tDegree/Double(tCount) : 0.0),
  199. fileType: self.fileType(),
  200. type: self.type())
  201. self._status = .Finished
  202. DispatchQueue.main.async {
  203. complention(self, self.reportString);
  204. }
  205. }
  206. }
  207. };
  208. }
  209. }
  210. }
  211. }
  212. // 启动第0号任务
  213. convertFileBlock(files);
  214. }
  215. }
  216. }else {
  217. _status = .Normal
  218. DispatchQueue.main.async {
  219. autoreleasepool {
  220. complention(self, nil)
  221. }
  222. }
  223. }
  224. }
  225. func process(_ originPath:String, resultPath:String, complention:@escaping (_ status:Int) -> ()) {
  226. return process(originPath, resultPath: resultPath, params: self.params(), complention: complention)
  227. }
  228. func process(_ originPath:String, resultPath:String, params:NSDictionary, complention:@escaping (_ status:Int) -> ()) {
  229. FileConverter.shared().converter(originPath, inDesPath: resultPath, params: params) { status in
  230. // 修复转 PNG 实际图片为 JPG 问题, 导致无法匹配问题
  231. if (NSArray(array: ["png", "PNG"]).contains(NSString(string: resultPath).pathExtension)) {
  232. let items = (FileManager.default.subpaths(atPath: resultPath) ?? []) as [String]
  233. for item in items {
  234. if NSArray(array: ["jpg", "JPG"]).contains(NSString(string:item).pathExtension) {
  235. let path = NSString(string: resultPath).appendingPathComponent(item);
  236. try? FileManager.default.moveItem(atPath: path,
  237. toPath: NSString(string: path).deletingPathExtension+".png");
  238. }
  239. }
  240. }
  241. complention(status)
  242. }
  243. }
  244. func compareResult(_ fileName:String, resultPath:String, status:Int, needCompare:Bool, complention:@escaping (_ degree:Double) -> ()) {
  245. NSLog("开始识别:\(fileName)")
  246. self.testlog("开始对比:"+fileName, (self.convertProgress + self.compareProgress)/2.0)
  247. let checkDirectory = self.checkFileDirectory()
  248. // let originDirectory = self.originFileDirectory()
  249. let resultDirectory = self.resultFileDirectory()
  250. let fName = NSString(string: fileName).deletingPathExtension
  251. var isDirectory = ObjCBool(false)
  252. if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) && status == 1 {
  253. // compare screenshoot between result file with check file
  254. if needCompare {
  255. let items = NSMutableArray()
  256. if (isDirectory.boolValue) {
  257. let searchItems = try! FileManager.default.contentsOfDirectory(atPath: resultPath)
  258. for item in NSArray(array: searchItems) {
  259. let ext = NSString(string: item as! String).pathExtension.lowercased()
  260. if (NSArray(array: [self.extention()]).contains(ext)) {
  261. let fileName = NSString(string: fName+"."+self.extention()+"/\(item as! String)").deletingPathExtension
  262. items.add(fileName)
  263. }
  264. }
  265. }else {
  266. items.add(fName)
  267. }
  268. var subDegree = Double(0);
  269. var subCount = Int(0)
  270. var itemIndex = 0;
  271. // let maxProcessCount = min(3, max(items.count, 1))
  272. var processItemBlock = {(items:NSMutableArray) in
  273. }
  274. processItemBlock = {(items:NSMutableArray) in
  275. if (itemIndex >= items.count) {
  276. // if (itemIndex >= (items.count + (maxProcessCount - 1))) {
  277. if subCount != 0 {
  278. subDegree = subDegree/Double(subCount)
  279. }else {
  280. subDegree = 0.0
  281. }
  282. TestDegreeManager.shared().set(subDegree,
  283. fileType: self.fileType(),
  284. type: self.type(),
  285. fileName: fileName)
  286. DispatchQueue.global().async {
  287. autoreleasepool {
  288. // 执行下一个文件转档
  289. complention(subDegree)
  290. NSLog("结束识别:\(fileName)");
  291. let index = self.testFiles.index(of: fileName);
  292. if (index != NSNotFound) {
  293. self.compareProgress = Double(index) / Double(self.testFiles.count)
  294. }
  295. self.compareFinishedFiles.add(fileName);
  296. self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
  297. }
  298. }
  299. // }
  300. return
  301. }
  302. DispatchQueue.global().async {
  303. autoreleasepool {
  304. let item = items[itemIndex]
  305. // NSLog("\(itemIndex):\(item)")
  306. let subFileName = item as! String
  307. let subResultPath = NSString(string: resultDirectory).appendingPathComponent(subFileName+"."+self.extention())
  308. objc_sync_enter(self)
  309. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subFileName+".\(self.extention())")\"快照生成中\n",
  310. attributes:[.foregroundColor : NSColor.black]))
  311. objc_sync_exit(self)
  312. let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg")
  313. let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg")
  314. ProcessThumbnal.process(subResultPath, desPath: rComparePath, outputSize: CGSize.init(width: 2048, height: 2048)) { processSuccess in
  315. autoreleasepool {
  316. if ( processSuccess &&
  317. FileManager.default.fileExists(atPath: rComparePath)) {
  318. var isDirectory = ObjCBool(false)
  319. if FileManager.default.fileExists(atPath: rComparePath, isDirectory: &isDirectory) && isDirectory.boolValue {
  320. // 单个文件生成批量快照目录情形
  321. let subImages = try! FileManager.default.contentsOfDirectory(atPath: rComparePath)
  322. var compareCount = 0;
  323. for sImageName in subImages {
  324. let subImageName = sImageName
  325. autoreleasepool {
  326. let pathCompotent = "/"+subImageName
  327. ImageProcess.compareJPEG(String(rComparePath+pathCompotent), checkPath: String(cComparePath+pathCompotent), processCover: true, complention: { degree in
  328. // NSLog(String("文件夹,\(subFileName+".jpg"+pathCompotent)"))
  329. TestDegreeManager.shared().set(degree, fileType: self.fileType(), type: self.type(),
  330. fileName: fileName, refFilePath: subFileName+".jpg"+pathCompotent)
  331. if degree == -1 {
  332. objc_sync_enter(self)
  333. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath+pathCompotent)\"快照对比失败,生成快照失败或无比对文件\n",
  334. attributes:[.foregroundColor : NSColor.red]))
  335. objc_sync_exit(self)
  336. }else {
  337. var color = NSColor.black
  338. if fabs(degree-100.0) >= 0.01 {
  339. color = NSColor.red
  340. }
  341. subDegree += degree
  342. subCount += 1
  343. objc_sync_enter(self)
  344. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath+pathCompotent)\"快照对比完成,图像相似度 \(degree)%\n",
  345. attributes:[.foregroundColor : color]))
  346. objc_sync_exit(self)
  347. }
  348. compareCount += 1
  349. if (compareCount >= subImages.count) {
  350. DispatchQueue.global().async {
  351. autoreleasepool {
  352. itemIndex += 1
  353. processItemBlock(items)
  354. }
  355. }
  356. }
  357. })
  358. }
  359. }
  360. if (subImages.count == 0) {
  361. // complention
  362. DispatchQueue.global().async {
  363. autoreleasepool {
  364. itemIndex += 1
  365. processItemBlock(items)
  366. }
  367. }
  368. return
  369. }
  370. }else {
  371. // 单个文件生成单个快照文件情形
  372. ImageProcess.compareJPEG(rComparePath, checkPath: cComparePath, processCover: true, complention: { degree in
  373. // NSLog(String("非文件夹,\(subFileName+".jpg")"))
  374. TestDegreeManager.shared().set(degree, fileType: self.fileType(), type: self.type(),
  375. fileName: fileName, refFilePath: subFileName+".jpg")
  376. if degree == -1 {
  377. objc_sync_enter(self)
  378. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath)\"快照对比失败,生成快照失败或无比对文件\n",
  379. attributes:[.foregroundColor : NSColor.red]))
  380. objc_sync_exit(self)
  381. }else {
  382. var color = NSColor.black
  383. if fabs(degree-100.0) >= 0.01 {
  384. color = NSColor.red
  385. }
  386. subDegree += degree
  387. subCount += 1
  388. objc_sync_enter(self)
  389. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath)\"快照对比完成,图像相似度 \(degree)%\n",
  390. attributes:[.foregroundColor : color]))
  391. objc_sync_exit(self)
  392. }
  393. // complention
  394. DispatchQueue.global().async {
  395. autoreleasepool {
  396. itemIndex += 1
  397. processItemBlock(items)
  398. }
  399. }
  400. })
  401. }
  402. }else {
  403. objc_sync_enter(self)
  404. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath)\"快照生成失败\n",
  405. attributes:[.foregroundColor : NSColor.red]))
  406. objc_sync_exit(self)
  407. // complention
  408. DispatchQueue.global().async {
  409. autoreleasepool {
  410. itemIndex += 1
  411. processItemBlock(items)
  412. }
  413. }
  414. }
  415. }
  416. }
  417. }
  418. }
  419. }
  420. processItemBlock(items)
  421. // while (itemIndex < (maxProcessCount - 1)) {
  422. // itemIndex += 1;
  423. // processItemBlock(items)
  424. // }
  425. return
  426. }
  427. }else {
  428. if (status == 0) {
  429. objc_sync_enter(self)
  430. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档失败!\n",
  431. attributes:[.foregroundColor : NSColor.red]))
  432. objc_sync_exit(self)
  433. }else if (status == -1 || status == -2) {
  434. objc_sync_enter(self)
  435. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"文档无法打开!\n",
  436. attributes:[.foregroundColor : NSColor.red]))
  437. objc_sync_exit(self)
  438. }else if (status == -3) {
  439. objc_sync_enter(self)
  440. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档中 Crash!\n",
  441. attributes:[.foregroundColor : NSColor.red]))
  442. objc_sync_exit(self)
  443. }
  444. }
  445. DispatchQueue.global().async {
  446. autoreleasepool {
  447. // 执行下一个文件转档
  448. NSLog("结束识别:\(fileName)");
  449. objc_sync_exit(self)
  450. let index = self.testFiles.index(of: fileName);
  451. if (index != NSNotFound) {
  452. self.compareProgress = Double(index) / Double(self.testFiles.count)
  453. }
  454. self.compareFinishedFiles.add(fileName);
  455. objc_sync_exit(self)
  456. self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
  457. complention(0)
  458. }
  459. }
  460. }
  461. ///
  462. func testReport() -> NSAttributedString? {
  463. return reportString
  464. }
  465. func degree() -> Double {
  466. return TestDegreeManager.shared().degreeFor(self.fileType(), type: self.type())
  467. }
  468. // func testReportOfFile(_ fileName:String) -> NSAttributedString? {
  469. //
  470. // }
  471. func degreeOfFile(_ fileName:String) -> Double {
  472. return TestDegreeManager.shared().degreeFor(self.fileType(), type: self.type(), fileName: fileName)
  473. }
  474. func degreeOfFile(_ fileName:String, refFilePath:String?) -> Double {
  475. if refFilePath != nil {
  476. return TestDegreeManager.shared().degreeFor(self.fileType(), type: self.type(), fileName: fileName, refFilePath: refFilePath)
  477. }else {
  478. return degreeOfFile(fileName)
  479. }
  480. }
  481. // Update Refrence image
  482. func canUpdateRefImage() -> Bool {
  483. let files = DataModel.shared.originFilesFor(_fileType, type: _type) as [String]
  484. let checkDirectory = self.checkFileDirectory()
  485. // let originDirectory = self.originFileDirectory()
  486. let resultDirectory = self.resultFileDirectory()
  487. for fileName:String in files {
  488. let fName = NSString(string: fileName).deletingPathExtension
  489. // let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
  490. let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention)
  491. // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention)
  492. var isDirectory = ObjCBool(false)
  493. if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) {
  494. // compare screenshoot between result file with check file
  495. let items = NSMutableArray()
  496. if (isDirectory.boolValue) {
  497. let searchItems = try! FileManager.default.contentsOfDirectory(atPath: resultPath)
  498. for item in NSArray(array: searchItems) {
  499. let ext = NSString(string: item as! String).pathExtension.lowercased()
  500. if NSArray(array: [_extention]).contains(ext) {
  501. let fileName = NSString(string: fName+"."+_extention+"/\(item as! String)").deletingPathExtension
  502. items.add(fileName)
  503. }
  504. }
  505. }else {
  506. items.add(fName)
  507. }
  508. for item in NSArray(array: items) {
  509. let subFileName = item as! String
  510. let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg")
  511. let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg")
  512. if FileManager.default.fileExists(atPath: rComparePath) {
  513. if !FileManager.default.fileExists(atPath: cComparePath) {
  514. return true
  515. }
  516. let rfs = try! FileManager.default.attributesOfItem(atPath: rComparePath)[FileAttributeKey.size] as! NSNumber
  517. let cfs = try! FileManager.default.attributesOfItem(atPath: cComparePath)[FileAttributeKey.size] as! NSNumber
  518. if rfs.int64Value != cfs.int64Value {
  519. return true
  520. }
  521. }
  522. }
  523. }
  524. }
  525. return false
  526. }
  527. func updateRefImage() {
  528. let files = DataModel.shared.originFilesFor(_fileType, type: _type) as [String]
  529. for fileName in files {
  530. updateRefImage(fileName)
  531. }
  532. }
  533. func canUpdateRefImage(_ fileName:String) -> Bool {
  534. let checkDirectory = self.checkFileDirectory()
  535. // let originDirectory = self.originFileDirectory()
  536. let resultDirectory = self.resultFileDirectory()
  537. let fName = NSString(string: fileName).deletingPathExtension
  538. // let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
  539. let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention)
  540. // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention)
  541. var isDirectory = ObjCBool(false)
  542. if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) {
  543. // compare screenshoot between result file with check file
  544. let items = NSMutableArray()
  545. if (isDirectory.boolValue) {
  546. let searchItems = try! FileManager.default.contentsOfDirectory(atPath: resultPath)
  547. for item in NSArray(array: searchItems) {
  548. let ext = NSString(string: item as! String).pathExtension.lowercased()
  549. if NSArray(array: [_extention]).contains(ext) {
  550. let fileName = NSString(string: fName+"."+_extention+"/\(item as! String)").deletingPathExtension
  551. items.add(fileName)
  552. }
  553. }
  554. }else {
  555. items.add(fName)
  556. }
  557. for item in NSArray(array: items) {
  558. let subFileName = item as! String
  559. let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg")
  560. let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg")
  561. if FileManager.default.fileExists(atPath: rComparePath) {
  562. if !FileManager.default.fileExists(atPath: cComparePath) {
  563. return true
  564. }
  565. let rfs = try! FileManager.default.attributesOfItem(atPath: rComparePath)[FileAttributeKey.size] as! NSNumber
  566. let cfs = try! FileManager.default.attributesOfItem(atPath: cComparePath)[FileAttributeKey.size] as! NSNumber
  567. if rfs.int64Value != cfs.int64Value {
  568. return true
  569. }
  570. }
  571. }
  572. }
  573. return false
  574. }
  575. func updateRefImage(_ fileName:String) {
  576. let checkDirectory = self.checkFileDirectory()
  577. // let originDirectory = self.originFileDirectory()
  578. let resultDirectory = self.resultFileDirectory()
  579. let fName = NSString(string: fileName).deletingPathExtension
  580. // let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
  581. let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention)
  582. // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention)
  583. var isDirectory = ObjCBool(false)
  584. if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) {
  585. // compare screenshoot between result file with check file
  586. let items = NSMutableArray()
  587. if (isDirectory.boolValue) {
  588. let searchItems = try! FileManager.default.contentsOfDirectory(atPath: resultPath)
  589. for item in NSArray(array: searchItems) {
  590. let ext = NSString(string: item as! String).pathExtension.lowercased()
  591. if NSArray(array: [_extention]).contains(ext) {
  592. let fileName = NSString(string: fName+"."+_extention+"/\(item as! String)").deletingPathExtension
  593. items.add(fileName)
  594. }
  595. }
  596. }else {
  597. items.add(fName)
  598. }
  599. for item in NSArray(array: items) {
  600. let subFileName = item as! String
  601. let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg")
  602. let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg")
  603. if FileManager.default.fileExists(atPath: rComparePath) {
  604. if FileManager.default.fileExists(atPath: cComparePath) {
  605. try! FileManager.default.removeItem(atPath: cComparePath)
  606. }
  607. try! FileManager.default.createDirectory(atPath: NSString(string: cComparePath).deletingLastPathComponent,
  608. withIntermediateDirectories: true)
  609. try! FileManager.default.copyItem(atPath: rComparePath, toPath: cComparePath)
  610. }
  611. }
  612. }
  613. }
  614. func compareFiles() -> NSArray? {
  615. let items = NSMutableArray()
  616. let files = DataModel.shared.originFilesFor(_fileType, type: _type) as [String]
  617. for fileName in files {
  618. let sItems = compareFiles(fileName)
  619. if sItems != nil && sItems!.count != 0 {
  620. items.addObjects(from: sItems as! [Any])
  621. }
  622. }
  623. return items
  624. }
  625. func compareFiles(_ fileName: String) -> NSArray? {
  626. let files = NSMutableArray()
  627. let checkDirectory = self.checkFileDirectory()
  628. // let originDirectory = self.originFileDirectory()
  629. let resultDirectory = self.resultFileDirectory()
  630. let fName = NSString(string: fileName).deletingPathExtension
  631. // let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
  632. let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention)
  633. // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention)
  634. var isDirectory = ObjCBool(false)
  635. if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) {
  636. // compare screenshoot between result file with check file
  637. let items = NSMutableArray()
  638. if (isDirectory.boolValue) {
  639. let searchItems = try? FileManager.default.contentsOfDirectory(atPath: resultPath)
  640. for item in NSArray(array: searchItems ?? []) {
  641. let ext = NSString(string: item as! String).pathExtension.lowercased()
  642. if (NSArray(array: [_extention]).contains(ext) &&
  643. !NSString(string: item as! String).contains("_cover.png")) {
  644. let fileName = NSString(string: fName+"."+_extention+"/\(item as! String)").deletingPathExtension
  645. items.add(fileName)
  646. }
  647. }
  648. }else {
  649. items.add(fName)
  650. }
  651. let nitems = items.sortedArray { str1, str2 in
  652. let s1 = NSString(string: str1 as! String).deletingPathExtension
  653. let s2 = NSString(string: str2 as! String).deletingPathExtension
  654. if (NSString(string: s1).length != NSString(string: s2).length) {
  655. if (NSString(string: s1).length > NSString(string: s2).length) {
  656. return .orderedDescending
  657. }else {
  658. return .orderedAscending
  659. }
  660. }
  661. return NSString(string: s1).compare(s2)
  662. }
  663. for item in nitems {
  664. let subFileName = item as! String
  665. let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg")
  666. let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg")
  667. let fileInfo = NSMutableDictionary.fileInfoWith(fileName,
  668. refFilePath: subFileName+".jpg",
  669. resultPath: rComparePath,
  670. comparePath: cComparePath,
  671. objc: self)
  672. files.add(fileInfo)
  673. }
  674. }
  675. return files
  676. }
  677. /// Path
  678. func originFileDirectory() -> String {
  679. return DataModel.shared.directoryPath().appendingFormat("/\(self.fileType())/\(self.type())/\(kOriginPathComponent)")
  680. }
  681. func resultFileDirectory() -> String {
  682. return DataModel.shared.directoryPath().appendingFormat("/\(self.fileType())/\(self.type())/\(kResultPathComponent)")
  683. }
  684. func checkFileDirectory() -> String {
  685. return DataModel.shared.directoryPath().appendingFormat("/\(self.fileType())/\(self.type())/\(kCheckPathComponent)")
  686. }
  687. // check File Exist
  688. func hasOriginFile() -> Bool {
  689. if FileManager.default.fileExists(atPath: self.originFileDirectory()) {
  690. let files = try? FileManager.default.subpathsOfDirectory(atPath: self.originFileDirectory())
  691. return (files ?? []).count > 0
  692. }
  693. return false
  694. }
  695. func hasResultFile() -> Bool {
  696. if FileManager.default.fileExists(atPath: self.resultFileDirectory()) {
  697. let files = try? FileManager.default.subpathsOfDirectory(atPath: self.resultFileDirectory())
  698. return (files ?? []).count > 0
  699. }
  700. return false
  701. }
  702. // Clear
  703. func clearCompareFiles() {
  704. reportString = NSMutableAttributedString.init();
  705. let resultDirectory = self.checkFileDirectory()
  706. var isDirectory = ObjCBool(false)
  707. if FileManager.default.fileExists(atPath: resultDirectory, isDirectory: &isDirectory) && isDirectory.boolValue {
  708. let searchItems = try? FileManager.default.contentsOfDirectory(atPath: resultDirectory)
  709. for item in NSArray(array: searchItems ?? []) {
  710. let path = NSString(string: resultDirectory).appendingPathComponent(item as! String)
  711. if FileManager.default.fileExists(atPath: path) {
  712. try? FileManager.default.removeItem(atPath: path)
  713. }
  714. }
  715. }
  716. }
  717. func clearOriginFiles() {
  718. reportString = NSMutableAttributedString.init();
  719. let resultDirectory = self.originFileDirectory()
  720. var isDirectory = ObjCBool(false)
  721. if FileManager.default.fileExists(atPath: resultDirectory, isDirectory: &isDirectory) && isDirectory.boolValue {
  722. let searchItems = try? FileManager.default.contentsOfDirectory(atPath: resultDirectory)
  723. for item in NSArray(array: searchItems ?? []) {
  724. let path = NSString(string: resultDirectory).appendingPathComponent(item as! String)
  725. if FileManager.default.fileExists(atPath: path) {
  726. try? FileManager.default.removeItem(atPath: path)
  727. }
  728. }
  729. }
  730. }
  731. func clearCacheFiles() {
  732. reportString = NSMutableAttributedString.init();
  733. let resultDirectory = self.resultFileDirectory()
  734. var isDirectory = ObjCBool(false)
  735. if FileManager.default.fileExists(atPath: resultDirectory, isDirectory: &isDirectory) && isDirectory.boolValue {
  736. let searchItems = try? FileManager.default.contentsOfDirectory(atPath: resultDirectory)
  737. for item in NSArray(array: searchItems ?? []) {
  738. let path = NSString(string: resultDirectory).appendingPathComponent(item as! String)
  739. if FileManager.default.fileExists(atPath: path) {
  740. try? FileManager.default.removeItem(atPath: path)
  741. }
  742. }
  743. }
  744. }
  745. }
  746. extension AutoTest {
  747. func stringToImage(_ string:String) ->NSImage? {
  748. let length = Int(string.lengthOfBytes(using: .utf8)/2)
  749. let bytes = malloc(length)!
  750. for i in 0..<length {
  751. let index = i
  752. let subString = String(NSString(string: string).substring(with: NSMakeRange(Int(index * 2), 2)))
  753. bytes.storeBytes(of: UInt8(hexForString(subString)), as: UInt8.self)
  754. }
  755. let data = Data.init(bytes: bytes, count: length)
  756. let image = NSImage.init(data: data)
  757. return image
  758. }
  759. func hexForString(_ string:String) -> UInt8 {
  760. let chars = string.utf8CString
  761. if (string.lengthOfBytes(using: .utf8) >= 2) {
  762. return UInt8(intvalueForChar(chars[0]) * 16 + intvalueForChar(chars[1]))
  763. }
  764. return UInt8(0)
  765. }
  766. func intvalueForChar(_ char:CChar) -> UInt8 {
  767. let iValue = char
  768. // 0 ~ 9s
  769. if iValue >= 48 && iValue <= 57 {
  770. return UInt8(iValue - 48)
  771. }else if iValue >= 65 && iValue <= 70 {
  772. return UInt8(iValue - 65 + 10)
  773. }else if iValue >= 97 && iValue <= 102 {
  774. return UInt8(iValue - 97 + 10)
  775. }
  776. return UInt8(0)
  777. }
  778. }
  779. extension AutoTest {
  780. func isEqual(to object: AutoTest) -> Bool {
  781. return (NSString(string: self.className).isEqual(to: object.className) &&
  782. NSString(string: self.fileType()).isEqual(to: object.fileType()) &&
  783. NSString(string: self.type()).isEqual(to: object.type()) &&
  784. NSString(string: self.extention()).isEqual(to: object.extention()))
  785. }
  786. }
  787. let kAutoTestObjectUpdateNotification = "kAutoTestObjectUpdateNotification"
  788. extension AutoTest {
  789. class func dateString() -> String {
  790. let date = NSDate.now
  791. return NSString(format: "%.0f", date.timeIntervalSince1970) as String
  792. }
  793. class func createObject(_ fileType:NSString, property:NSDictionary) -> AutoTest? {
  794. let key = fileType as String
  795. var ID = property.value(forKey: "ID") as? String
  796. if nil != ID && cacheObjects.value(forKey: key) != nil {
  797. let objectInfo = cacheObjects.value(forKey: key) as! NSMutableDictionary
  798. if objectInfo.value(forKey: ID!) != nil {
  799. let object = objectInfo.value(forKey: ID!)
  800. return object as? AutoTest
  801. }
  802. }
  803. var objectInfo = cacheObjects.value(forKey: key) as? NSMutableDictionary
  804. if (nil == objectInfo) {
  805. objectInfo = NSMutableDictionary()
  806. cacheObjects.setValue(objectInfo, forKey: key)
  807. }
  808. let params = NSMutableDictionary(dictionary: property)
  809. if nil == ID {
  810. ID = AutoTest.dateString()
  811. params.setValue(ID!, forKey: "ID")
  812. }
  813. let cID = params["ID"] as! NSString
  814. let cType = params["Type"] as! NSString
  815. let cExtention = params["Extention"] as! NSString
  816. let cName = params["Name"] as! NSString
  817. let cParams = params["Params"] as? NSDictionary
  818. let clsname = "KdanAuto"//Bundle.main.infoDictionary! ["CFBundleExecutable"]
  819. let className = String((clsname )+"."+(params["Class"] as! String))
  820. let cl = NSClassFromString(className) as! AutoTest.Type
  821. let object = cl.shared()
  822. object?.m_id = cID as String
  823. object?.m_info = params
  824. object?._fileType = fileType as String
  825. object?._type = String(cType)
  826. object?._extention = String(cExtention)
  827. object?._name = String(cName)
  828. if nil != cParams {
  829. object?._params = cParams ?? [:];
  830. }
  831. objectInfo!.setValue(object, forKey: ID!)
  832. AutoTest.saveObjects()
  833. return object
  834. }
  835. func update(_ property:NSDictionary) {
  836. let cID = property["ID"] as! NSString
  837. let cType = property["Type"] as! NSString
  838. let cExtention = property["Extention"] as! NSString
  839. let cName = property["Name"] as! NSString
  840. let cParams = property["Params"] as? NSDictionary
  841. self.m_id = cID as String
  842. self.m_info = property
  843. self._type = String(cType)
  844. self._extention = String(cExtention)
  845. self._name = String(cName)
  846. if nil != cParams {
  847. self._params = cParams ?? [:];
  848. }
  849. AutoTest.saveObjects()
  850. }
  851. func delete() {
  852. let key = self.fileType() as String
  853. var ID = self.m_id as? String
  854. self.clearCacheFiles()
  855. self.clearOriginFiles()
  856. self.clearCompareFiles()
  857. let directory = NSString(string: self.originFileDirectory()).deletingLastPathComponent
  858. try? FileManager.default.removeItem(atPath: directory)
  859. if nil != ID && cacheObjects.value(forKey: key) != nil {
  860. let objectInfo = cacheObjects.value(forKey: key) as! NSMutableDictionary
  861. if objectInfo.value(forKey: ID!) != nil {
  862. let object = objectInfo.value(forKey: ID!)
  863. objectInfo.setValue(nil, forKey: ID!)
  864. }
  865. AutoTest.saveObjects()
  866. }
  867. }
  868. class func saveObjects() {
  869. let propertyInfo = NSMutableDictionary();
  870. for key in testFileTypes {
  871. let fileType = key
  872. let property = NSMutableArray()
  873. propertyInfo.setValue(property, forKey: fileType)
  874. let objectInfo = cacheObjects.value(forKey: key) as? NSMutableDictionary
  875. if (objectInfo != nil) {
  876. for obj in objectInfo!.allValues {
  877. let object = obj as? AutoTest
  878. if (object?.m_info != nil) {
  879. property.add(object!.m_info)
  880. }
  881. }
  882. }
  883. }
  884. var path = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first?.appending("/CustomAutoTestProperty.plist")
  885. NSLog("Save Path:\(path)")
  886. propertyInfo.write(toFile: path!, atomically: true)
  887. testTypeInfo = propertyInfo as NSDictionary
  888. NotificationCenter.default.post(name: NSNotification.Name(kAutoTestObjectUpdateNotification), object: nil)
  889. }
  890. }