AutoTest.swift 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  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. if nil != ID && cacheObjects.value(forKey: key) != nil {
  855. let objectInfo = cacheObjects.value(forKey: key) as! NSMutableDictionary
  856. if objectInfo.value(forKey: ID!) != nil {
  857. let object = objectInfo.value(forKey: ID!)
  858. objectInfo.setValue(nil, forKey: ID!)
  859. }
  860. AutoTest.saveObjects()
  861. }
  862. }
  863. class func saveObjects() {
  864. let propertyInfo = NSMutableDictionary();
  865. for key in testFileTypes {
  866. let fileType = key
  867. let property = NSMutableArray()
  868. propertyInfo.setValue(property, forKey: fileType)
  869. let objectInfo = cacheObjects.value(forKey: key) as? NSMutableDictionary
  870. if (objectInfo != nil) {
  871. for obj in objectInfo!.allValues {
  872. let object = obj as? AutoTest
  873. if (object?.m_info != nil) {
  874. property.add(object!.m_info)
  875. }
  876. }
  877. }
  878. }
  879. var path = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first?.appending("/CustomAutoTestProperty.plist")
  880. NSLog("Save Path:\(path)")
  881. propertyInfo.write(toFile: path!, atomically: true)
  882. testTypeInfo = propertyInfo as NSDictionary
  883. NotificationCenter.default.post(name: NSNotification.Name(kAutoTestObjectUpdateNotification), object: nil)
  884. }
  885. }