AutoTest.swift 54 KB

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