// // AutoTest.swift // KdanAuto // // Created by 朱东勇 on 2022/11/25. // import Foundation import AppKit var cacheObjects = NSMutableDictionary() let operateQueue = OperationQueue() class AutoTest : NSObject, AutoTestProtocal { var reportString : NSMutableAttributedString? = nil public var _status : AutoTestStatus = .Normal var m_info:NSDictionary! var _fileType : String = "RTF" var m_id : String = "" var _type : String = "Others" var _extention : String = "rtf" var _name : String = "对照测试" var _params : NSDictionary = [:] var testFiles : NSArray = NSArray() var convertFiles : NSMutableArray = NSMutableArray() var convertProgress : Double = 0.0 var compareFinishedFiles : NSMutableArray = NSMutableArray() var compareProgress : Double = 0.0 var testlog : (_ msg:String, _ progress:Double) -> () = {(msg, progress) in } class func autoTestFor(_ fileType:NSString ,id:NSString) -> AutoTest? { let cFileType = fileType let key = String(fileType) let ID = String(id) if cacheObjects.value(forKey: key) != nil { let objectInfo = cacheObjects.value(forKey: key) as! NSMutableDictionary if objectInfo.value(forKey: ID) != nil { let object = objectInfo.value(forKey: ID) return object as? AutoTest } } let fileTypes = testTypeInfo[cFileType] as! NSArray let clsname = "KdanAuto"//Bundle.main.infoDictionary! ["CFBundleExecutable"] var objectInfo = cacheObjects.value(forKey: key) as? NSMutableDictionary if (nil == objectInfo) { objectInfo = NSMutableDictionary() cacheObjects.setValue(objectInfo, forKey: key) } for item in fileTypes { let cItem = item as! NSDictionary let cID = cItem["ID"] as! NSString let cType = cItem["Type"] as! NSString let cExtention = cItem["Extention"] as! NSString let cName = cItem["Name"] as! NSString let cParams = cItem["Params"] as? NSDictionary if (cID.isEqual(to: ID)) { let className = String((clsname )+"."+(cItem["Class"] as! String)) let cl = NSClassFromString(className) as! AutoTest.Type let object = cl.shared() object?.m_id = cID as String object?.m_info = cItem object?._fileType = cFileType as String object?._type = String(cType) object?._extention = String(cExtention) object?._name = String(cName) if nil != cParams { object?._params = cParams ?? [:]; } objectInfo!.setValue(object, forKey: ID) return object } } let object = AutoTest.shared() object?.m_id = id as String object?._fileType = cFileType as String object?._type = String(cType) object?._extention = "" object?._name = "对照测试" objectInfo!.setValue(object, forKey: ID) return object } class func shared() -> AutoTest? { return AutoTest() } func fileType() -> String { return _fileType } func type() -> String { return _type } func name() -> String { return _name } func extention() -> String { return _extention } func params() -> NSDictionary { return _params } func keys() -> NSArray { return ["快照"] } func selectedKeys() -> NSArray { let userDefaults = UserDefaults.standard let key = self.fileType() + "." + self.type() + ".selectedKeys" if userDefaults.value(forKey: key) != nil { return userDefaults.value(forKey: key) as! NSArray } self.setSelectedKeys(self.keys()) return self.keys() } func setSelectedKeys(_ keys: NSArray) { let userDefaults = UserDefaults.standard let key = self.fileType() + "." + self.type() + ".selectedKeys" userDefaults.setValue(keys, forKey: key) userDefaults.synchronize() } func needCompareTest() -> Bool { return self.selectedKeys().contains("快照") } func needTest() -> Bool { return needCompareTest() } func status() -> AutoTestStatus { return _status } func setStatus(_ status:AutoTestStatus) { _status = status } // Auto Test func autoTest(_ complention:@escaping (_ object:AutoTest, _ report:NSAttributedString?) -> ()) { self.compareFinishedFiles.removeAllObjects(); self.convertFiles.removeAllObjects() NSLog(String("转换\(self.type())")) // if (LogViewController.shared().isVisable()) { // LogViewController.shared().appendLog("\n***开始转换\(self.type())***\n") // } let needCompare = self.selectedKeys().contains("快照") if !needCompare { // 未勾选 ”快照“ 选项 self._status = .Finished complention(self, self.reportString) return } clearCacheFiles() if hasOriginFile() { //目录中有需要执行对照的文件 DispatchQueue.global().async { autoreleasepool { self._status = .Process self.reportString = NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】快照比对开始!\n", attributes:[.foregroundColor : NSColor.blue]) let files = DataModel.shared.originFilesFor(self.fileType(), type: self.type()) as [String] self.testFiles = NSArray(array: files); let checkDirectory = self.checkFileDirectory() let originDirectory = self.originFileDirectory() let resultDirectory = self.resultFileDirectory() if (files.count > 0) { try? FileManager.default.createDirectory(atPath: checkDirectory, withIntermediateDirectories: true); try? FileManager.default.createDirectory(atPath: resultDirectory, withIntermediateDirectories: true); } var tDegree = Double(0); var tCount = Int(0) var fileIndex = 0 var compareIndex = 0; var convertFinished = false; // 用 Block 递归调用形式,确保转档单任务执行 var convertFileBlock = { (files:[String]) in } convertFileBlock = { (files:[String]) in if (fileIndex >= files.count) { convertFinished = true; return } // let fileName = files[fileIndex]; autoreleasepool { let checkDirectory = self.checkFileDirectory() let originDirectory = self.originFileDirectory() let resultDirectory = self.resultFileDirectory() let fName = NSString(string: fileName).deletingPathExtension let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf") let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+self.extention()) // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention) // self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】开始转换文件 \"\(fName)\"\n", // attributes:[.foregroundColor : NSColor.blue])) // ... // 执行异步转换过程 let index = self.testFiles.index(of: fileName); if (index != NSNotFound) { self.convertProgress = Double(index) / Double(self.testFiles.count) } self.convertFiles.add(fileName); self.testlog("开始转换:"+fileName, (self.compareProgress + self.convertProgress)/2.0) self.process(originPath, resultPath: resultPath) { status in DispatchQueue.global().async { Thread.sleep(forTimeInterval: 0.3) fileIndex += 1; convertFileBlock(files) self.compareResult(fileName, resultPath: resultPath, status: status, needCompare: needCompare) { degree in autoreleasepool { if (degree >= 0.0) { tDegree += degree; tCount += 1; } compareIndex += 1; if (convertFinished && compareIndex >= files.count) { //所有任务已经执行完成 TestDegreeManager.shared().set(((tCount != 0) ? tDegree/Double(tCount) : 0.0), fileType: self.fileType(), type: self.type()) self._status = .Finished DispatchQueue.main.async { complention(self, self.reportString); } } } }; } } } } // 启动第0号任务 convertFileBlock(files); } } }else { _status = .Normal DispatchQueue.main.async { autoreleasepool { complention(self, nil) } } } } func process(_ originPath:String, resultPath:String, complention:@escaping (_ status:Int) -> ()) { return process(originPath, resultPath: resultPath, params: self.params(), complention: complention) } func process(_ originPath:String, resultPath:String, params:NSDictionary, complention:@escaping (_ status:Int) -> ()) { FileConverter.shared().converter(originPath, inDesPath: resultPath, params: params) { status in // 修复转 PNG 实际图片为 JPG 问题, 导致无法匹配问题 if (NSArray(array: ["png", "PNG"]).contains(NSString(string: resultPath).pathExtension)) { let items = (FileManager.default.subpaths(atPath: resultPath) ?? []) as [String] for item in items { if NSArray(array: ["jpg", "JPG"]).contains(NSString(string:item).pathExtension) { let path = NSString(string: resultPath).appendingPathComponent(item); try? FileManager.default.moveItem(atPath: path, toPath: NSString(string: path).deletingPathExtension+".png"); } } } complention(status) } } func compareResult(_ fileName:String, resultPath:String, status:Int, needCompare:Bool, complention:@escaping (_ degree:Double) -> ()) { NSLog("开始识别:\(fileName)") // if (LogViewController.shared().isVisable()) { // LogViewController.shared().appendLog("开始对比:\(fileName)\n") // } self.testlog("开始对比:"+fileName, (self.convertProgress + self.compareProgress)/2.0) let checkDirectory = self.checkFileDirectory() // let originDirectory = self.originFileDirectory() let resultDirectory = self.resultFileDirectory() let fName = NSString(string: fileName).deletingPathExtension var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) && status == 1 { // compare screenshoot between result file with check file if needCompare { let items = NSMutableArray() if (isDirectory.boolValue) { let searchItems = try! FileManager.default.contentsOfDirectory(atPath: resultPath) for item in NSArray(array: searchItems) { let ext = NSString(string: item as! String).pathExtension.lowercased() if (NSArray(array: [self.extention()]).contains(ext)) { let fileName = NSString(string: fName+"."+self.extention()+"/\(item as! String)").deletingPathExtension items.add(fileName) } } }else { items.add(fName) } var subDegree = Double(0); var subCount = Int(0) var itemIndex = 0; // let maxProcessCount = min(3, max(items.count, 1)) var processItemBlock = {(items:NSMutableArray) in } processItemBlock = {(items:NSMutableArray) in if (itemIndex >= items.count) { // if (itemIndex >= (items.count + (maxProcessCount - 1))) { if subCount != 0 { subDegree = subDegree/Double(subCount) }else { subDegree = 0.0 } TestDegreeManager.shared().set(subDegree, fileType: self.fileType(), type: self.type(), fileName: fileName) DispatchQueue.global().async { autoreleasepool { // 执行下一个文件转档 complention(subDegree) NSLog("结束识别:\(fileName)"); // if (LogViewController.shared().isVisable()) { // LogViewController.shared().appendLog("对比完成:\(fileName)\n") // } let index = self.testFiles.index(of: fileName); if (index != NSNotFound) { self.compareProgress = Double(index) / Double(self.testFiles.count) } self.compareFinishedFiles.add(fileName); self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0) } } // } return } DispatchQueue.global().async { autoreleasepool { let item = items[itemIndex] // NSLog("\(itemIndex):\(item)") let subFileName = item as! String let subResultPath = NSString(string: resultDirectory).appendingPathComponent(subFileName+"."+self.extention()) objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subFileName+".\(self.extention())")\"快照生成中\n", attributes:[.foregroundColor : NSColor.black])) objc_sync_exit(self) let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg") let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg") ProcessThumbnal.process(subResultPath, desPath: rComparePath, outputSize: CGSize.init(width: 2048, height: 2048)) { processSuccess in autoreleasepool { if ( processSuccess && FileManager.default.fileExists(atPath: rComparePath)) { var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: rComparePath, isDirectory: &isDirectory) && isDirectory.boolValue { // 单个文件生成批量快照目录情形 let subImages = try! FileManager.default.contentsOfDirectory(atPath: rComparePath) var compareCount = 0; for sImageName in subImages { let subImageName = sImageName autoreleasepool { let pathCompotent = "/"+subImageName ImageProcess.compareJPEG(String(rComparePath+pathCompotent), checkPath: String(cComparePath+pathCompotent), processCover: true, complention: { degree in // NSLog(String("文件夹,\(subFileName+".jpg"+pathCompotent)")) TestDegreeManager.shared().set(degree, fileType: self.fileType(), type: self.type(), fileName: fileName, refFilePath: subFileName+".jpg"+pathCompotent) if degree == -1 { objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath+pathCompotent)\"快照对比失败,生成快照失败或无比对文件\n", attributes:[.foregroundColor : NSColor.red])) objc_sync_exit(self) }else { var color = NSColor.black if fabs(degree-100.0) >= 0.01 { color = NSColor.red } subDegree += degree subCount += 1 objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath+pathCompotent)\"快照对比完成,图像相似度 \(degree)%\n", attributes:[.foregroundColor : color])) objc_sync_exit(self) } compareCount += 1 if (compareCount >= subImages.count) { DispatchQueue.global().async { autoreleasepool { itemIndex += 1 processItemBlock(items) } } } }) } } if (subImages.count == 0) { // complention DispatchQueue.global().async { autoreleasepool { itemIndex += 1 processItemBlock(items) } } return } }else { // 单个文件生成单个快照文件情形 ImageProcess.compareJPEG(rComparePath, checkPath: cComparePath, processCover: true, complention: { degree in // NSLog(String("非文件夹,\(subFileName+".jpg")")) TestDegreeManager.shared().set(degree, fileType: self.fileType(), type: self.type(), fileName: fileName, refFilePath: subFileName+".jpg") if degree == -1 { objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath)\"快照对比失败,生成快照失败或无比对文件\n", attributes:[.foregroundColor : NSColor.red])) objc_sync_exit(self) }else { var color = NSColor.black if fabs(degree-100.0) >= 0.01 { color = NSColor.red } subDegree += degree subCount += 1 objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath)\"快照对比完成,图像相似度 \(degree)%\n", attributes:[.foregroundColor : color])) objc_sync_exit(self) } // complention DispatchQueue.global().async { autoreleasepool { itemIndex += 1 processItemBlock(items) } } }) } }else { objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(subResultPath)\"快照生成失败\n", attributes:[.foregroundColor : NSColor.red])) objc_sync_exit(self) // complention DispatchQueue.global().async { autoreleasepool { itemIndex += 1 processItemBlock(items) } } } } } } } } processItemBlock(items) // while (itemIndex < (maxProcessCount - 1)) { // itemIndex += 1; // processItemBlock(items) // } return } }else { if (status == 0) { objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档失败!\n", attributes:[.foregroundColor : NSColor.red])) objc_sync_exit(self) }else if (status == -1 || status == -2) { objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"文档无法打开!\n", attributes:[.foregroundColor : NSColor.red])) objc_sync_exit(self) }else if (status == -3) { objc_sync_enter(self) self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档中 Crash!\n", attributes:[.foregroundColor : NSColor.red])) objc_sync_exit(self) } } DispatchQueue.global().async { autoreleasepool { // 执行下一个文件转档 NSLog("结束识别:\(fileName)"); // if (LogViewController.shared().isVisable()) { // LogViewController.shared().appendLog("对比完成:\(fileName)\n") // } objc_sync_exit(self) let index = self.testFiles.index(of: fileName); if (index != NSNotFound) { self.compareProgress = Double(index) / Double(self.testFiles.count) } self.compareFinishedFiles.add(fileName); objc_sync_exit(self) self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0) complention(0) } } } /// func testReport() -> NSAttributedString? { return reportString } func degree() -> Double { return TestDegreeManager.shared().degreeFor(self.fileType(), type: self.type()) } // func testReportOfFile(_ fileName:String) -> NSAttributedString? { // // } func degreeOfFile(_ fileName:String) -> Double { return TestDegreeManager.shared().degreeFor(self.fileType(), type: self.type(), fileName: fileName) } func degreeOfFile(_ fileName:String, refFilePath:String?) -> Double { if refFilePath != nil { return TestDegreeManager.shared().degreeFor(self.fileType(), type: self.type(), fileName: fileName, refFilePath: refFilePath) }else { return degreeOfFile(fileName) } } // Update Refrence image func canUpdateRefImage() -> Bool { let files = DataModel.shared.originFilesFor(_fileType, type: _type) as [String] let checkDirectory = self.checkFileDirectory() // let originDirectory = self.originFileDirectory() let resultDirectory = self.resultFileDirectory() for fileName:String in files { let fName = NSString(string: fileName).deletingPathExtension // let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf") let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention) // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention) var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) { // compare screenshoot between result file with check file let items = NSMutableArray() if (isDirectory.boolValue) { let searchItems = try! FileManager.default.contentsOfDirectory(atPath: resultPath) for item in NSArray(array: searchItems) { let ext = NSString(string: item as! String).pathExtension.lowercased() if NSArray(array: [_extention]).contains(ext) { let fileName = NSString(string: fName+"."+_extention+"/\(item as! String)").deletingPathExtension items.add(fileName) } } }else { items.add(fName) } for item in NSArray(array: items) { let subFileName = item as! String let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg") let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg") if FileManager.default.fileExists(atPath: rComparePath) { if !FileManager.default.fileExists(atPath: cComparePath) { return true } let rfs = try! FileManager.default.attributesOfItem(atPath: rComparePath)[FileAttributeKey.size] as! NSNumber let cfs = try! FileManager.default.attributesOfItem(atPath: cComparePath)[FileAttributeKey.size] as! NSNumber if rfs.int64Value != cfs.int64Value { return true } } } } } return false } func updateRefImage() { let files = DataModel.shared.originFilesFor(_fileType, type: _type) as [String] for fileName in files { updateRefImage(fileName) } } func canUpdateRefImage(_ fileName:String) -> Bool { let checkDirectory = self.checkFileDirectory() // let originDirectory = self.originFileDirectory() let resultDirectory = self.resultFileDirectory() let fName = NSString(string: fileName).deletingPathExtension // let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf") let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention) // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention) var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) { // compare screenshoot between result file with check file let items = NSMutableArray() if (isDirectory.boolValue) { let searchItems = try! FileManager.default.contentsOfDirectory(atPath: resultPath) for item in NSArray(array: searchItems) { let ext = NSString(string: item as! String).pathExtension.lowercased() if NSArray(array: [_extention]).contains(ext) { let fileName = NSString(string: fName+"."+_extention+"/\(item as! String)").deletingPathExtension items.add(fileName) } } }else { items.add(fName) } for item in NSArray(array: items) { let subFileName = item as! String let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg") let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg") if FileManager.default.fileExists(atPath: rComparePath) { if !FileManager.default.fileExists(atPath: cComparePath) { return true } let rfs = try! FileManager.default.attributesOfItem(atPath: rComparePath)[FileAttributeKey.size] as! NSNumber let cfs = try! FileManager.default.attributesOfItem(atPath: cComparePath)[FileAttributeKey.size] as! NSNumber if rfs.int64Value != cfs.int64Value { return true } } } } return false } func updateRefImage(_ fileName:String) { let checkDirectory = self.checkFileDirectory() // let originDirectory = self.originFileDirectory() let resultDirectory = self.resultFileDirectory() let fName = NSString(string: fileName).deletingPathExtension // let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf") let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention) // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention) var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) { // compare screenshoot between result file with check file let items = NSMutableArray() if (isDirectory.boolValue) { let searchItems = try! FileManager.default.contentsOfDirectory(atPath: resultPath) for item in NSArray(array: searchItems) { let ext = NSString(string: item as! String).pathExtension.lowercased() if NSArray(array: [_extention]).contains(ext) { let fileName = NSString(string: fName+"."+_extention+"/\(item as! String)").deletingPathExtension items.add(fileName) } } }else { items.add(fName) } for item in NSArray(array: items) { let subFileName = item as! String let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg") let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg") if FileManager.default.fileExists(atPath: rComparePath) { if FileManager.default.fileExists(atPath: cComparePath) { try! FileManager.default.removeItem(atPath: cComparePath) } try! FileManager.default.createDirectory(atPath: NSString(string: cComparePath).deletingLastPathComponent, withIntermediateDirectories: true) try! FileManager.default.copyItem(atPath: rComparePath, toPath: cComparePath) } } } } func compareFiles() -> NSArray? { let items = NSMutableArray() let files = DataModel.shared.originFilesFor(_fileType, type: _type) as [String] for fileName in files { let sItems = compareFiles(fileName) if sItems != nil && sItems!.count != 0 { items.addObjects(from: sItems as! [Any]) } } return items } func compareFiles(_ fileName: String) -> NSArray? { let files = NSMutableArray() let checkDirectory = self.checkFileDirectory() // let originDirectory = self.originFileDirectory() let resultDirectory = self.resultFileDirectory() let fName = NSString(string: fileName).deletingPathExtension // let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf") let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention) // let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention) var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: resultPath, isDirectory:&isDirectory) { // compare screenshoot between result file with check file let items = NSMutableArray() if (isDirectory.boolValue) { let searchItems = try? FileManager.default.contentsOfDirectory(atPath: resultPath) for item in NSArray(array: searchItems ?? []) { let ext = NSString(string: item as! String).pathExtension.lowercased() if (NSArray(array: [_extention]).contains(ext) && !NSString(string: item as! String).contains("_cover.png")) { let fileName = NSString(string: fName+"."+_extention+"/\(item as! String)").deletingPathExtension items.add(fileName) } } }else { items.add(fName) } let nitems = items.sortedArray { str1, str2 in let s1 = NSString(string: str1 as! String).deletingPathExtension let s2 = NSString(string: str2 as! String).deletingPathExtension if (NSString(string: s1).length != NSString(string: s2).length) { if (NSString(string: s1).length > NSString(string: s2).length) { return .orderedDescending }else { return .orderedAscending } } return NSString(string: s1).compare(s2) } for item in nitems { let subFileName = item as! String let rComparePath = NSString(string: resultDirectory).appendingPathComponent(subFileName+".jpg") let cComparePath = NSString(string: checkDirectory).appendingPathComponent(subFileName+".jpg") let fileInfo = NSMutableDictionary.fileInfoWith(fileName, refFilePath: subFileName+".jpg", resultPath: rComparePath, comparePath: cComparePath, objc: self) files.add(fileInfo) } } return files } /// Path func originFileDirectory() -> String { return DataModel.shared.directoryPath().appendingFormat("/\(self.fileType())/\(self.type())/\(kOriginPathComponent)") } func resultFileDirectory() -> String { return DataModel.shared.directoryPath().appendingFormat("/\(self.fileType())/\(self.type())/\(kResultPathComponent)") } func checkFileDirectory() -> String { return DataModel.shared.directoryPath().appendingFormat("/\(self.fileType())/\(self.type())/\(kCheckPathComponent)") } // check File Exist func hasOriginFile() -> Bool { if FileManager.default.fileExists(atPath: self.originFileDirectory()) { let files = try? FileManager.default.subpathsOfDirectory(atPath: self.originFileDirectory()) return (files ?? []).count > 0 } return false } func hasResultFile() -> Bool { if FileManager.default.fileExists(atPath: self.resultFileDirectory()) { let files = try? FileManager.default.subpathsOfDirectory(atPath: self.resultFileDirectory()) return (files ?? []).count > 0 } return false } // Clear func clearCompareFiles() { reportString = NSMutableAttributedString.init(); let resultDirectory = self.checkFileDirectory() var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: resultDirectory, isDirectory: &isDirectory) && isDirectory.boolValue { let searchItems = try? FileManager.default.contentsOfDirectory(atPath: resultDirectory) for item in NSArray(array: searchItems ?? []) { let path = NSString(string: resultDirectory).appendingPathComponent(item as! String) if FileManager.default.fileExists(atPath: path) { try? FileManager.default.removeItem(atPath: path) } } } } func clearOriginFiles() { reportString = NSMutableAttributedString.init(); let resultDirectory = self.originFileDirectory() var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: resultDirectory, isDirectory: &isDirectory) && isDirectory.boolValue { let searchItems = try? FileManager.default.contentsOfDirectory(atPath: resultDirectory) for item in NSArray(array: searchItems ?? []) { let path = NSString(string: resultDirectory).appendingPathComponent(item as! String) if FileManager.default.fileExists(atPath: path) { try? FileManager.default.removeItem(atPath: path) } } } } func clearCacheFiles() { reportString = NSMutableAttributedString.init(); let resultDirectory = self.resultFileDirectory() var isDirectory = ObjCBool(false) if FileManager.default.fileExists(atPath: resultDirectory, isDirectory: &isDirectory) && isDirectory.boolValue { let searchItems = try? FileManager.default.contentsOfDirectory(atPath: resultDirectory) for item in NSArray(array: searchItems ?? []) { let path = NSString(string: resultDirectory).appendingPathComponent(item as! String) if FileManager.default.fileExists(atPath: path) { try? FileManager.default.removeItem(atPath: path) } } } } } extension AutoTest { func stringToImage(_ string:String) ->NSImage? { let length = Int(string.lengthOfBytes(using: .utf8)/2) let bytes = malloc(length)! for i in 0.. UInt8 { let chars = string.utf8CString if (string.lengthOfBytes(using: .utf8) >= 2) { return UInt8(intvalueForChar(chars[0]) * 16 + intvalueForChar(chars[1])) } return UInt8(0) } func intvalueForChar(_ char:CChar) -> UInt8 { let iValue = char // 0 ~ 9s if iValue >= 48 && iValue <= 57 { return UInt8(iValue - 48) }else if iValue >= 65 && iValue <= 70 { return UInt8(iValue - 65 + 10) }else if iValue >= 97 && iValue <= 102 { return UInt8(iValue - 97 + 10) } return UInt8(0) } } extension AutoTest { func isEqual(to object: AutoTest) -> Bool { return (NSString(string: self.className).isEqual(to: object.className) && NSString(string: self.fileType()).isEqual(to: object.fileType()) && NSString(string: self.type()).isEqual(to: object.type()) && NSString(string: self.extention()).isEqual(to: object.extention())) } } let kAutoTestObjectUpdateNotification = "kAutoTestObjectUpdateNotification" extension AutoTest { class func dateString() -> String { let date = NSDate() return NSString(format: "%.0f", date.timeIntervalSince1970) as String } class func createObject(_ fileType:NSString, property:NSDictionary) -> AutoTest? { NSLog("\(fileType):\(property)") let key = fileType as String var ID = property.value(forKey: "ID") as? String if nil != ID && cacheObjects.value(forKey: key) != nil { let objectInfo = cacheObjects.value(forKey: key) as! NSMutableDictionary if objectInfo.value(forKey: ID!) != nil { let object = objectInfo.value(forKey: ID!) return object as? AutoTest } } var objectInfo = cacheObjects.value(forKey: key) as? NSMutableDictionary if (nil == objectInfo) { objectInfo = NSMutableDictionary() cacheObjects.setValue(objectInfo, forKey: key) } let params = NSMutableDictionary(dictionary: property) if nil == ID { ID = AutoTest.dateString() params.setValue(ID!, forKey: "ID") } let cID = params["ID"] as! NSString let cType = params["Type"] as! NSString let cExtention = params["Extention"] as! NSString let cName = params["Name"] as! NSString let cParams = params["Params"] as? NSDictionary let clsname = "KdanAuto"//Bundle.main.infoDictionary! ["CFBundleExecutable"] let className = String((clsname )+"."+(params["Class"] as! String)) let cl = NSClassFromString(className) as! AutoTest.Type let object = cl.shared() object?.m_id = cID as String object?.m_info = NSDictionary(dictionary: params) object?._fileType = fileType as String object?._type = String(cType) object?._extention = String(cExtention) object?._name = String(cName) if nil != cParams { object?._params = cParams ?? [:]; } objectInfo!.setValue(object, forKey: ID!) AutoTest.saveObjects() return object } func update(_ property:NSDictionary) -> AutoTest? { let cClass = property["Class"] as! NSString let oClass = self.m_info["Class"] as! NSString let cID = property["ID"] as! NSString let cType = property["Type"] as! NSString let cExtention = property["Extention"] as! NSString let cName = property["Name"] as! NSString let cParams = property["Params"] as? NSDictionary var object = self; if (cClass.isEqual(to: oClass)) { self.m_id = cID as String self.m_info = NSDictionary(dictionary: property) self._type = String(cType) self._extention = String(cExtention) self._name = String(cName) if nil != cParams { self._params = cParams ?? [:]; } }else { let fileType = self.fileType() as String let key = self.fileType() as String let ID = cID // 移除原来的Object if cacheObjects.value(forKey: key) != nil { let objectInfo = cacheObjects.value(forKey: key) as! NSMutableDictionary if objectInfo.value(forKey: ID as String) != nil { objectInfo.setValue(nil, forKey: ID as String) } } var objectInfo = cacheObjects.value(forKey: key) as? NSMutableDictionary if (nil == objectInfo) { objectInfo = NSMutableDictionary() cacheObjects.setValue(objectInfo, forKey: key) } let params = NSMutableDictionary(dictionary: property) let clsname = "KdanAuto"//Bundle.main.infoDictionary! ["CFBundleExecutable"] let className = String((clsname )+"."+(params["Class"] as! String)) let cl = NSClassFromString(className) as! AutoTest.Type object = cl.shared()! object.m_id = ID as String object.m_info = NSDictionary(dictionary: params) object._fileType = fileType object._type = String(cType) object._extention = String(cExtention) object._name = String(cName) if nil != cParams { object._params = cParams ?? [:]; } objectInfo!.setValue(object, forKey: ID as String) } AutoTest.saveObjects() return object } func delete() { let key = self.fileType() as String var ID = self.m_id as? String self.clearCacheFiles() self.clearOriginFiles() self.clearCompareFiles() let directory = NSString(string: self.originFileDirectory()).deletingLastPathComponent try? FileManager.default.removeItem(atPath: directory) if nil != ID && cacheObjects.value(forKey: key) != nil { let objectInfo = cacheObjects.value(forKey: key) as! NSMutableDictionary if objectInfo.value(forKey: ID!) != nil { let object = objectInfo.value(forKey: ID!) objectInfo.setValue(nil, forKey: ID!) } AutoTest.saveObjects() } } class func saveObjects() { let propertyInfo = NSMutableDictionary(); for key in testFileTypes { let fileType = key let property = NSMutableArray() propertyInfo.setValue(property, forKey: fileType) let objectInfo = cacheObjects.value(forKey: key) as? NSMutableDictionary if (objectInfo != nil) { for obj in objectInfo!.allValues { let object = obj as? AutoTest if (object?.m_info != nil) { property.add(object!.m_info) } } } } var path = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first?.appending("/CustomAutoTestProperty.plist") NSLog("Save Path:\(path)") propertyInfo.write(toFile: path!, atomically: true) testTypeInfo = propertyInfo as NSDictionary NotificationCenter.default.post(name: NSNotification.Name(kAutoTestObjectUpdateNotification), object: nil) } }