StringAutoTest.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. //
  2. // CharacterAutoTest.swift
  3. // KdanAuto
  4. //
  5. // Created by 朱东勇 on 2022/11/22.
  6. //
  7. import Foundation
  8. import Cocoa
  9. class CharacterAutoTest : AutoTest {
  10. // override func type() -> String {
  11. // return "PDFConvert_China_Auto_Test"
  12. // }
  13. override func name() -> String {
  14. return _name
  15. }
  16. override func keys() -> NSArray {
  17. return ["字符", "快照"]
  18. }
  19. static var cSharedInstance = CharacterAutoTest()
  20. override class func shared() -> AutoTest? {
  21. return cSharedInstance
  22. }
  23. // Auto Test refrence Check File
  24. override func autoTest(_ complention:@escaping (_ object:AutoTest, _ report:NSAttributedString?) -> ()) {
  25. clearCacheFiles()
  26. let checkString = self.selectedKeys().contains("字符")
  27. let needCompare = self.selectedKeys().contains("快照")
  28. if !needCompare && !checkString {
  29. _status = .Finished
  30. complention(self, self.reportString)
  31. return
  32. }
  33. _status = .Process
  34. reportString = NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】字符比对开始!\n",
  35. attributes:[.foregroundColor : NSColor.blue])
  36. let files = DataModel.shared.originFilesFor(_fileType, type: _type)
  37. let checkDirectory = self.checkFileDirectory()
  38. let originDirectory = self.originFileDirectory()
  39. let resultDirectory = self.resultFileDirectory()
  40. if (files.count > 0) {
  41. try? FileManager.default.createDirectory(atPath: checkDirectory, withIntermediateDirectories: true);
  42. try? FileManager.default.createDirectory(atPath: resultDirectory, withIntermediateDirectories: true);
  43. }
  44. var tDegree = Double(0);
  45. var tCount = Int(0)
  46. var fileIndex = 0;
  47. var convertFileBlock = { (files:[String]) in }
  48. convertFileBlock = { (files:[String]) in
  49. if (fileIndex >= files.count) {
  50. TestDegreeManager.shared().set(((tCount != 0) ? tDegree/Double(tCount) : 0.0),
  51. fileType: self.fileType(),
  52. type: self.type())
  53. self._status = .Finished
  54. DispatchQueue.main.async {
  55. autoreleasepool {
  56. complention(self, self.reportString);
  57. }
  58. }
  59. return
  60. }
  61. let fileName = files[fileIndex]
  62. let fName = NSString(string: fileName).deletingPathExtension
  63. let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
  64. let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+self.extention())
  65. let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+self.extention())
  66. self.reportString?.append(NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】开始转换文件 \"\(fName)\"\n",
  67. attributes:[.foregroundColor : NSColor.black]))
  68. // ...
  69. // 执行转换过程
  70. self.process(originPath, resultPath: resultPath) { status in
  71. if FileManager.default.fileExists(atPath: resultPath) && status == 1 {
  72. if checkString && FileManager.default.fileExists(atPath: checkPath) {
  73. // Load check file
  74. let checkData = NSData.init(contentsOfFile: checkPath) as! Data
  75. var documentAttributes:NSDictionary!
  76. let checkAttString = NSAttributedString.init(rtf: checkData, documentAttributes: &documentAttributes)
  77. var checkString = NSString(string: checkAttString!.string) as NSString
  78. let resultString = try? NSString.init(contentsOfFile: resultPath, encoding: NSUTF8StringEncoding)
  79. #if false
  80. //识别字符串 \shptxt\shptxt ... }
  81. let pageInfoStrings = resultString!.components(separatedBy: "\\shptxt\\shptxt") as NSArray
  82. var finalString = ""
  83. if pageInfoStrings.count > 0 {
  84. let subStrings = pageInfoStrings.subarray(with: NSMakeRange(1, Int(pageInfoStrings.count - 1))) as! [String]
  85. for pageInfoString in subStrings {
  86. let endRange = NSString(string: pageInfoString).range(of: "}")
  87. finalString = finalString.appending(NSString(string: pageInfoString).substring(to: endRange.location))
  88. }
  89. }
  90. //识别所有 【空格 ~ \】 之间的值,并进行缝合
  91. // Detect all strings between Spaces and \ and stitch
  92. let strings = finalString.components(separatedBy: " ")
  93. var resultStr = "" as NSString
  94. for str in strings {
  95. let markStr = str as NSString
  96. if (markStr.contains("\\f")) {
  97. let fRange = markStr.range(of: "\\f")
  98. let cRange = markStr.range(of: "\\c")
  99. let bRange = markStr.range(of: "\\b")
  100. let iRange = markStr.range(of: "\\i")
  101. let eRange = markStr.range(of: "\\e")
  102. let pRange = markStr.range(of: "\\p")
  103. let minPos = min(Int(fRange.location),
  104. Int(cRange.location),
  105. Int(bRange.location),
  106. Int(iRange.location),
  107. Int(eRange.location),
  108. Int(pRange.location))
  109. resultStr = resultStr.appending(markStr.substring(to: minPos)) as NSString
  110. }else {
  111. resultStr = resultStr.appending(markStr as String) as NSString
  112. }
  113. }
  114. resultStr = self.replaceUnicodeString(resultStr)
  115. #else
  116. let resultData = NSData.init(contentsOfFile: resultPath) as! Data
  117. var rDocumentAttributes:NSDictionary!
  118. let resultAttString = NSAttributedString.init(rtf: resultData, documentAttributes: &rDocumentAttributes)
  119. var resultStr = NSString(string: resultAttString!.string)
  120. #endif
  121. resultStr = resultStr.replacingOccurrences(of: "\n", with: "") as NSString
  122. checkString = checkString.replacingOccurrences(of: "\n", with: "") as NSString
  123. resultStr = resultStr.replacingOccurrences(of: " ", with: "") as NSString
  124. checkString = checkString.replacingOccurrences(of: " ", with: "") as NSString
  125. resultStr = resultStr.replacingOccurrences(of: "\\pard", with: "") as NSString
  126. resultStr = resultStr.replacingOccurrences(of: "\\par", with: "") as NSString
  127. // do { // save cache file for test
  128. // try? NSString(string: resultStr).write(toFile: NSString(string: DataModel.shared.resultPath()).appending("/\(self.name())-result-cache.txt"),
  129. // atomically: true, encoding: NSUTF8StringEncoding)
  130. //
  131. // try? NSString(string: checkString).write(toFile: NSString(string: DataModel.shared.resultPath()).appending("/\(self.name())-check-cache.txt"),
  132. // atomically: true, encoding: NSUTF8StringEncoding)
  133. // }
  134. let maxSize = checkString.length
  135. var successCount = 0;
  136. /**
  137. (A0 = B0)
  138. - A-1 & B-1
  139. (A0 != B0) & (A0 in B) & (B0 in A)
  140. - 取 A0,B0最小 Range 值
  141. - 字符串裁剪对齐
  142. (A0 != B0) & (A0 in B)
  143. - 存储B0到识别错误缓存
  144. (A0 != B0) & (B0 in A)
  145. - 存储 A0到识别遗漏字符串
  146. (A0 != B0)
  147. - 分别存储 A0、B0到遗漏及错误字串
  148. */
  149. var skipString = NSString()
  150. var failString = NSString()
  151. while (checkString.length > 0 && resultStr.length > 0) {
  152. let subc = checkString.substring(to: 1) as NSString
  153. let subr = resultStr.substring(to: 1) as NSString
  154. if subc.isEqual(to: subr) { // (A0 = B0)
  155. // Check Success
  156. self.appendErrorInfo(skipString, failString: failString)
  157. skipString = NSString()
  158. failString = NSString()
  159. checkString = checkString.substring(from:1) as NSString
  160. resultStr = resultStr.substring(from:1) as NSString
  161. successCount = successCount + 1
  162. }else if (checkString.contains(subr as String) && resultStr.contains(subc as String)) {
  163. self.appendErrorInfo(skipString, failString: failString)
  164. skipString = NSString()
  165. failString = NSString()
  166. let cRange = checkString.range(of: subr as String)
  167. let rRange = resultStr.range(of: subc as String)
  168. if (cRange.location < rRange.location) {
  169. let cacheString = checkString.substring(to:cRange.location + cRange.length)
  170. self.reportString?.append(NSMutableAttributedString.init(string: "对照字符串【\(cacheString)】未识别到\n",
  171. attributes:[.foregroundColor : NSColor.red]))
  172. checkString = checkString.substring(from:cRange.location) as NSString
  173. }else {
  174. let cacheString = resultStr.substring(to:rRange.location)
  175. self.reportString?.append(NSMutableAttributedString.init(string: "字符串【\(cacheString)】识别出错\n",
  176. attributes:[.foregroundColor : NSColor.red]))
  177. resultStr = resultStr.substring(from:rRange.location + rRange.length) as NSString
  178. }
  179. }else if (checkString.contains(subr as String)) {
  180. skipString = skipString.appending(subc as String) as NSString
  181. checkString = checkString.substring(from:1) as NSString
  182. }else if (resultStr.contains(subc as String)) {
  183. failString = failString.appending(subr as String) as NSString
  184. resultStr = resultStr.substring(from:1) as NSString
  185. }else {
  186. skipString = skipString.appending(subc as String) as NSString
  187. failString = failString.appending(subr as String) as NSString
  188. checkString = checkString.substring(from:1) as NSString
  189. resultStr = resultStr.substring(from:1) as NSString
  190. }
  191. }
  192. skipString = skipString.appending(checkString as String) as NSString
  193. failString = failString.appending(resultStr as String) as NSString
  194. self.appendErrorInfo(skipString, failString: failString)
  195. let degree = Float(successCount)/Float(maxSize) * 100
  196. var color = NSColor.black
  197. if fabs(degree-100.0) >= 0.01 {
  198. color = NSColor.red
  199. }
  200. self.reportString?.append(NSAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"比对完成,准确率\(degree)%(\(successCount)/\(maxSize))\n",
  201. attributes:[.foregroundColor : color]))
  202. }
  203. // compare screenshoot between result file with check file
  204. if needCompare {
  205. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"快照生成中\n",
  206. attributes:[.foregroundColor : NSColor.black]))
  207. let rComparePath = NSString(string: resultDirectory).appendingPathComponent(fName+".jpg")
  208. let cComparePath = NSString(string: checkDirectory).appendingPathComponent(fName+".jpg")
  209. let processThumbSemaphore = DispatchSemaphore(value: 0)
  210. var processSuccess = false
  211. let thumbnailQueue = DispatchQueue.global()
  212. thumbnailQueue.async {
  213. autoreleasepool {
  214. processSuccess = ProcessThumbnal.process(resultPath, desPath: rComparePath, outputSize: CGSize.init(width: 2048, height: 2048))
  215. if (processSuccess &&
  216. FileManager.default.fileExists(atPath: rComparePath)) {
  217. let degree = ImageProcess.compareJPEG(rComparePath, checkPath: cComparePath, processCover: true)
  218. if degree == -1 {
  219. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"快照对比失败,生成快照失败或无比对文件\n",
  220. attributes:[.foregroundColor : NSColor.red]))
  221. }else {
  222. var color = NSColor.black
  223. if fabs(degree-100.0) >= 0.01 {
  224. color = NSColor.red
  225. }
  226. TestDegreeManager.shared().set(degree,
  227. fileType: self.fileType(),
  228. type: self.type(),
  229. fileName: fileName);
  230. TestDegreeManager.shared().set(degree,
  231. fileType: self.fileType(),
  232. type: self.type(),
  233. fileName: fileName,
  234. refFilePath: fName+".jpg");
  235. tDegree += degree
  236. tCount += 1
  237. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"快照对比完成,图像相似度 \(degree)%\n",
  238. attributes:[.foregroundColor : color]))
  239. }
  240. }else {
  241. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"快照生成失败\n",
  242. attributes:[.foregroundColor : NSColor.red]))
  243. }
  244. processThumbSemaphore.signal()
  245. }
  246. }
  247. processThumbSemaphore.wait()
  248. }
  249. }else {
  250. if (status == 0) {
  251. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档失败!\n",
  252. attributes:[.foregroundColor : NSColor.red]))
  253. }else if (status == -1 || status == -2) {
  254. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"文档无法打开!\n",
  255. attributes:[.foregroundColor : NSColor.red]))
  256. }else if (status == -3) {
  257. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档中 Crash!\n",
  258. attributes:[.foregroundColor : NSColor.red]))
  259. }
  260. }
  261. fileIndex += 1
  262. convertFileBlock(files);
  263. }
  264. }
  265. convertFileBlock(files);
  266. }
  267. ///Compare
  268. /// Tools
  269. func appendErrorInfo(_ skipString:NSString, failString: NSString) {
  270. if skipString.length > 0 && failString.length > 0 {
  271. reportString?.append(NSMutableAttributedString.init(string: "对比字符串【\(skipString)】错识别为【\(failString)】\n",
  272. attributes:[.foregroundColor : NSColor.red]))
  273. }else if (skipString.length > 0) {
  274. reportString?.append(NSMutableAttributedString.init(string: "对比字符串【\(skipString)】未识别到\n",
  275. attributes:[.foregroundColor : NSColor.red]))
  276. }else if failString.length > 0 {
  277. reportString?.append(NSMutableAttributedString.init(string: "字符串【\(failString)】识别出错\n",
  278. attributes:[.foregroundColor : NSColor.red]))
  279. }
  280. }
  281. func replaceUnicodeString(_ string:NSString) -> NSString {//中
  282. let items = string.components(separatedBy: "\\u") as [NSString]
  283. var resultString = NSString()
  284. for item in items {
  285. if (item.contains("?")) {
  286. let unicodeValue = item.intValue
  287. let skipRange = item.range(of: "?")
  288. let nextString = item.substring(from: Int(skipRange.location + skipRange.length)) as NSString
  289. let bytes : [UInt8] = [UInt8(unicodeValue/256),UInt8(unicodeValue%256)]
  290. let data = NSData.init(bytes: bytes, length: 2)
  291. let unicodeString = NSString.init(data: data as Data, encoding: NSUnicodeStringEncoding)! as NSString
  292. resultString = resultString.appending(String("\(unicodeString)\(nextString)")) as NSString
  293. }else {
  294. resultString = resultString.appending(String(item)) as NSString
  295. }
  296. }
  297. return resultString
  298. }
  299. }