Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

634 lines
50KB

  1. Option Explicit
  2. Const ForReading = 1
  3. Const TristateFalse = 0
  4. Const TristateTrue = -1
  5. Dim fso:Set fso = CreateObject("Scripting.FileSystemObject")
  6. Dim scriptDir: scriptDir = fso.GetParentFolderName(WScript.ScriptFullName)
  7. Dim repoRoot: repoRoot = fso.GetParentFolderName(scriptDir)
  8. Dim sourcePath: sourcePath = fso.BuildPath(repoRoot, "ImportService\\TrackingDataImport.vbs")
  9. Dim chilkatSerialPath: chilkatSerialPath = fso.BuildPath(scriptDir, "chillkat_serial")
  10. Dim objFSO
  11. Dim DataDirectory
  12. Dim objCSV ' Required for ValidImportCSV
  13. Dim oConn
  14. Dim ConnectionString
  15. Dim ExportDirectory
  16. Dim integrationMdbPath
  17. Dim integrationExportDir
  18. Dim integrationDbAvailable
  19. Dim integrationDbSkipReason
  20. Dim wow64CScript
  21. Dim is64BitHost
  22. Dim sh
  23. Dim oExec
  24. Dim InkjetExportSortDirection
  25. Dim functionNames
  26. functionNames = Array( _
  27. "PadLeft", _
  28. "CheckForFiles", _
  29. "Truncate", _
  30. "PadString", _
  31. "CleanNull", _
  32. "Assign", _
  33. "Choice", _
  34. "CompressArray", _
  35. "TrimLeadingZeros", _
  36. "PushNonEmptyToBottom", _
  37. "GetState", _
  38. "GetCityFromLine", _
  39. "CheckStringDoesNotHaveForiegnCountries", _
  40. "ValidImportCSV", _
  41. "GetSetting", _
  42. "ExportInkjetFile" _
  43. )
  44. LoadFunctions sourcePath, functionNames
  45. Set objFSO = fso
  46. ' Initialize Chilkat CSV if available (required for ValidImportCSV tests)
  47. Dim chilkatAvailable
  48. Dim chilkatReason: chilkatReason = ""
  49. On Error Resume Next
  50. Dim glob
  51. Set glob = CreateObject("Chilkat_9_5_0.Global")
  52. If Err.Number <> 0 Then
  53. chilkatReason = "Chilkat_9_5_0.Global COM not available"
  54. Err.Clear
  55. Else
  56. Dim serialNumber: serialNumber = LoadChilkatSerial(chilkatSerialPath)
  57. If Len(serialNumber) = 0 Then
  58. chilkatReason = "missing serial in " & chilkatSerialPath
  59. Else
  60. Dim unlockSuccess: unlockSuccess = glob.UnlockBundle(serialNumber)
  61. If unlockSuccess <> 1 Then
  62. chilkatReason = "unlock failed"
  63. If Len(Trim(glob.LastErrorText & "")) > 0 Then
  64. chilkatReason = chilkatReason & " - " & Replace(Trim(glob.LastErrorText & ""), vbCrLf, " ")
  65. End If
  66. Else
  67. Set objCSV = CreateObject("Chilkat_9_5_0.Csv")
  68. If Err.Number = 0 Then
  69. chilkatAvailable = True
  70. Else
  71. chilkatReason = "Chilkat_9_5_0.Csv COM not available"
  72. Err.Clear
  73. End If
  74. End If
  75. End If
  76. End If
  77. On Error GoTo 0
  78. ' === Integration test DB probe ===
  79. wow64CScript = "C:\Windows\SysWOW64\cscript.exe"
  80. is64BitHost = (InStr(1, LCase(WScript.FullName), "syswow64") = 0) And fso.FileExists(wow64CScript)
  81. integrationMdbPath = fso.BuildPath(scriptDir, "..\Data\webdata - Copy.mdb")
  82. integrationExportDir = fso.BuildPath(scriptDir, "export-test-output")
  83. integrationDbAvailable = False
  84. integrationDbSkipReason = ""
  85. If Not fso.FileExists(integrationMdbPath) Then
  86. integrationDbSkipReason = "MDB fixture not found: " & integrationMdbPath
  87. Else
  88. Set oConn = CreateObject("ADODB.Connection")
  89. On Error Resume Next
  90. oConn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & integrationMdbPath & ";"
  91. If Err.Number <> 0 Then
  92. Err.Clear
  93. oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & integrationMdbPath & ";"
  94. End If
  95. If Err.Number <> 0 Then
  96. Dim failDesc : failDesc = Err.Description
  97. Err.Clear
  98. On Error GoTo 0
  99. If is64BitHost Then
  100. ' 64-bit cscript can't see 32-bit ACE/Jet drivers — re-run as 32-bit and relay output
  101. WScript.Echo "64-bit cscript: ADODB driver not found. Re-running as 32-bit cscript..."
  102. Set sh = CreateObject("WScript.Shell")
  103. Set oExec = sh.Exec("cmd /c " & wow64CScript & " //NoLogo " & Chr(34) & WScript.ScriptFullName & Chr(34) & " 2>&1")
  104. Do While Not oExec.StdOut.AtEndOfStream
  105. WScript.Echo oExec.StdOut.ReadLine()
  106. Loop
  107. WScript.Quit oExec.ExitCode
  108. Else
  109. integrationDbSkipReason = "No ADODB provider available (ACE and Jet both failed): " & failDesc
  110. End If
  111. Else
  112. integrationDbAvailable = True
  113. ConnectionString = oConn.ConnectionString
  114. ExportDirectory = integrationExportDir & "\"
  115. End If
  116. On Error GoTo 0
  117. If oConn.State = 1 Then oConn.Close
  118. End If
  119. Dim passed: passed = 0
  120. Dim failed: failed = 0
  121. Dim q: q = Chr(34)
  122. AssertEqual Truncate("abcdef", 3), q & "abc" & q & ",", "Truncate trims and quotes"
  123. AssertEqual Truncate("ab", 3), q & "ab" & q & ",", "Truncate short string"
  124. AssertEqual PadLeft("7", 3, "0"), "007", "PadLeft pads"
  125. AssertEqual PadLeft("1234", 3, "0"), "1234", "PadLeft no pad when longer"
  126. AssertEqual PadString("ab", 4), "ab ", "PadString right pads"
  127. AssertEqual PadString("abcd", 4), "abcd", "PadString same length"
  128. AssertEqual PadString(Null, 3), " ", "PadString null"
  129. AssertEqual CleanNull(Null), "", "CleanNull null"
  130. AssertEqual CleanNull("x"), "x", "CleanNull value"
  131. Dim arr
  132. arr = Array("", "a", "", "b")
  133. arr = CompressArray(arr)
  134. AssertArrayEqual arr, Array("a", "b", "", ""), "CompressArray moves blanks to end"
  135. AssertEqual TrimLeadingZeros("000123"), "123", "TrimLeadingZeros removes leading zeros"
  136. AssertEqual TrimLeadingZeros("0000"), "", "TrimLeadingZeros all zeros"
  137. Dim arr2
  138. arr2 = Array("a", "", "b", "")
  139. PushNonEmptyToBottom arr2
  140. AssertArrayEqual arr2, Array("", "", "a", "b"), "PushNonEmptyToBottom"
  141. AssertEqual GetState("Lansing, MI 48906"), "MI", "GetState matches state"
  142. AssertEqual GetState("No match"), "", "GetState no match"
  143. AssertEqual GetCityFromLine("Lansing, MI 48906"), "Lansing", "GetCityFromLine with comma"
  144. AssertEqual GetCityFromLine("NoComma"), "NoComma", "GetCityFromLine no comma"
  145. AssertEqual GetCityFromLine(Null), "", "GetCityFromLine null"
  146. Dim tempDir
  147. tempDir = fso.BuildPath(repoRoot, "Tests\\_tmp_checkforfiles")
  148. If Not fso.FolderExists(tempDir) Then
  149. fso.CreateFolder tempDir
  150. End If
  151. Set objFSO = fso
  152. DataDirectory = tempDir
  153. On Error Resume Next
  154. Dim checkResult
  155. checkResult = CheckForFiles()
  156. If Err.Number = 0 Then
  157. passed = passed + 1
  158. WScript.Echo "PASS: CheckForFiles runs without error (empty dir)"
  159. Else
  160. failed = failed + 1
  161. WScript.Echo "FAIL: CheckForFiles error " & Err.Number & " - " & Err.Description
  162. Err.Clear
  163. End If
  164. On Error GoTo 0
  165. ' === [P0] CheckStringDoesNotHaveForiegnCountries ===
  166. AssertEqual CheckStringDoesNotHaveForiegnCountries("123 Main St, Lansing MI 48906"), True, "[P0] CheckStringDoesNotHaveForiegnCountries clean US address"
  167. AssertEqual CheckStringDoesNotHaveForiegnCountries("123 Main St, CANADA"), False, "[P0] CheckStringDoesNotHaveForiegnCountries CANADA uppercase match"
  168. AssertEqual CheckStringDoesNotHaveForiegnCountries("Tokyo, JAPAN 12345"), False, "[P0] CheckStringDoesNotHaveForiegnCountries JAPAN uppercase match"
  169. AssertEqual CheckStringDoesNotHaveForiegnCountries("123 Norway Ave, Lansing MI"), True, "[P0] CheckStringDoesNotHaveForiegnCountries Norway Ave (behavior doc: InStr binary, Norway<>NORWAY)"
  170. AssertEqual CheckStringDoesNotHaveForiegnCountries("123 canada road"), True, "[P0] CheckStringDoesNotHaveForiegnCountries lowercase canada (behavior doc: case-sensitive, no match)"
  171. AssertEqual CheckStringDoesNotHaveForiegnCountries(""), True, "[P0] CheckStringDoesNotHaveForiegnCountries empty string"
  172. AssertEqual CheckStringDoesNotHaveForiegnCountries(Null), True, "[P0] CheckStringDoesNotHaveForiegnCountries null (InStr returns Null, falsy in If)"
  173. ' === [P0] GetState additional ===
  174. AssertEqual GetState("lansing, mi 48906"), "", "[P0] GetState lowercase state returns empty (behavior doc: IgnoreCase=False, mixed-case CSV misses)"
  175. AssertEqual GetState(""), "", "[P0] GetState empty string"
  176. ' === [P0] Choice with Null condition ===
  177. AssertEqual Choice(Null, "yes", "no"), "no", "[P0] Choice null condition evaluates as False branch"
  178. ' === [P0] ValidImportCSV (requires Chilkat_9_5_0.Csv COM) ===
  179. If chilkatAvailable Then
  180. Dim csv20col
  181. csv20col = "H1,H2,H3,H4,H5,H6,H7,H8,H9,H10,H11,H12,H13,H14,H15,H16,H17,H18,H19,H20" & vbCrLf & _
  182. "v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20"
  183. AssertEqual ValidImportCSV(csv20col), True, "[P0] ValidImportCSV 20 columns accepted"
  184. Dim csv19col
  185. csv19col = "H1,H2,H3,H4,H5,H6,H7,H8,H9,H10,H11,H12,H13,H14,H15,H16,H17,H18,H19" & vbCrLf & _
  186. "v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19"
  187. AssertEqual ValidImportCSV(csv19col), False, "[P0] ValidImportCSV 19 columns rejected"
  188. AssertEqual ValidImportCSV(""), False, "[P0] ValidImportCSV empty string rejected"
  189. Else
  190. WScript.Echo "SKIP: ValidImportCSV tests skipped (" & chilkatReason & ")"
  191. End If
  192. ' === [P1] TrimLeadingZeros edge cases ===
  193. AssertEqual TrimLeadingZeros(""), "", "[P1] TrimLeadingZeros empty string"
  194. AssertEqual TrimLeadingZeros("abc"), "abc", "[P1] TrimLeadingZeros no leading zeros"
  195. AssertEqual TrimLeadingZeros("0"), "", "[P1] TrimLeadingZeros single zero"
  196. AssertEqual TrimLeadingZeros(" 007"), " 007", "[P1] TrimLeadingZeros leading space preserved (space is not zero)"
  197. ' === [P1] PadLeft edge cases ===
  198. AssertEqual PadLeft("007", 3, "0"), "007", "[P1] PadLeft exact length no padding"
  199. AssertEqual PadLeft("", 3, "0"), "000", "[P1] PadLeft empty string padded"
  200. ' === [P1] PadString edge cases ===
  201. AssertEqual PadString("abcde", 3), "abcde", "[P1] PadString longer than size returned as-is"
  202. AssertEqual PadString("", 3), " ", "[P1] PadString empty string padded to spaces"
  203. ' === [P1] CompressArray edge cases ===
  204. Dim arr3
  205. arr3 = Array("", "", "")
  206. arr3 = CompressArray(arr3)
  207. AssertArrayEqual arr3, Array("", "", ""), "[P1] CompressArray all-empty array unchanged"
  208. Dim arr4
  209. arr4 = Array("a", "b", "c")
  210. arr4 = CompressArray(arr4)
  211. AssertArrayEqual arr4, Array("a", "b", "c"), "[P1] CompressArray all-non-empty no swaps"
  212. Dim arr5
  213. arr5 = Array("a")
  214. arr5 = CompressArray(arr5)
  215. AssertArrayEqual arr5, Array("a"), "[P1] CompressArray single element"
  216. ' === [P2] Assign ===
  217. Dim v1
  218. Assign v1, "hello"
  219. AssertEqual v1, "hello", "[P2] Assign scalar string"
  220. Assign v1, 42
  221. AssertEqual v1, 42, "[P2] Assign scalar number"
  222. Assign v1, ""
  223. AssertEqual v1, "", "[P2] Assign empty string"
  224. Assign v1, 0
  225. AssertEqual v1, 0, "[P2] Assign zero"
  226. ' === [P2] Choice ===
  227. AssertEqual Choice(True, "yes", "no"), "yes", "[P2] Choice True branch"
  228. AssertEqual Choice(False, "yes", "no"), "no", "[P2] Choice False branch"
  229. AssertEqual Choice(1 = 1, "equal", "not"), "equal", "[P2] Choice computed True"
  230. AssertEqual Choice(1 = 2, "equal", "not"), "not", "[P2] Choice computed False"
  231. ' === ExportInkjetFile Integration Test ===
  232. If Not chilkatAvailable Then
  233. WScript.Echo "SKIP: ExportInkjetFile integration test (Chilkat unavailable)"
  234. ElseIf Not integrationDbAvailable Then
  235. WScript.Echo "SKIP: ExportInkjetFile integration test (" & integrationDbSkipReason & ")"
  236. Else
  237. oConn.Open ConnectionString
  238. Dim kitDiscoverRs
  239. Set kitDiscoverRs = oConn.Execute( _
  240. "SELECT TOP 1 ir.KitID FROM ((InkjetRecords ir " & _
  241. "INNER JOIN Kit k ON ir.KitID = k.ID) " & _
  242. "INNER JOIN Jurisdiction j ON k.JCode = j.JCode) " & _
  243. "INNER JOIN Contacts c ON k.JCode = c.JURISCODE WHERE ir.ID IN (SELECT TOP 500 ID FROM InkjetRecords ORDER BY ID);")
  244. If kitDiscoverRs.EOF Then
  245. WScript.Echo "SKIP: ExportInkjetFile - no complete Kit+InkjetRecords+Jurisdiction+Contact found in fixture MDB"
  246. oConn.Close
  247. Else
  248. Dim testKitID : testKitID = kitDiscoverRs("KitID").Value
  249. Dim countRs
  250. Set countRs = oConn.Execute("SELECT COUNT(*) AS N FROM InkjetRecords WHERE KitID=" & testKitID & ";")
  251. Dim expectedRows : expectedRows = countRs("N").Value
  252. Dim kitRsCheck
  253. Set kitRsCheck = oConn.Execute("SELECT JCode FROM Kit WHERE ID=" & testKitID & ";")
  254. Dim testJCode : testJCode = kitRsCheck("JCode").Value
  255. oConn.Close
  256. Dim descCsvPath : descCsvPath = RunExportInkjetScenario(testKitID, "" , "DESC")
  257. If Len(descCsvPath) > 0 Then
  258. AssertExportInkjetCsv testKitID, descCsvPath, expectedRows, testJCode, "DESC"
  259. End If
  260. Dim ascCsvPath : ascCsvPath = RunExportInkjetScenario(testKitID, "ASC", "ASC")
  261. If Len(ascCsvPath) > 0 Then
  262. AssertExportInkjetCsv testKitID, ascCsvPath, expectedRows, testJCode, "ASC"
  263. End If
  264. oConn.Open ConnectionString
  265. Dim sideEffectRs
  266. Set sideEffectRs = oConn.Execute("SELECT Status, InkJetJob FROM Kit WHERE ID=" & testKitID & ";")
  267. AssertEqual sideEffectRs("Status").Value, "Done", "[INT] ExportInkjetFile: Kit.Status = Done"
  268. Dim ijVal : ijVal = sideEffectRs("InkJetJob").Value
  269. Dim ijSet : ijSet = False
  270. If Not IsNull(ijVal) Then ijSet = CBool(ijVal)
  271. AssertEqual ijSet, True, "[INT] ExportInkjetFile: Kit.InkJetJob is set"
  272. oConn.Close
  273. ' Cleanup - error-suppressed (AV may briefly hold CSV handle)
  274. On Error Resume Next
  275. If fso.FolderExists(integrationExportDir) Then fso.DeleteFolder integrationExportDir, True
  276. If fso.FolderExists(fso.BuildPath(scriptDir, "export-test-output-desc")) Then fso.DeleteFolder fso.BuildPath(scriptDir, "export-test-output-desc"), True
  277. If fso.FolderExists(fso.BuildPath(scriptDir, "export-test-output-asc")) Then fso.DeleteFolder fso.BuildPath(scriptDir, "export-test-output-asc"), True
  278. On Error GoTo 0
  279. End If
  280. End If
  281. WScript.Echo ""
  282. WScript.Echo "Passed: " & passed
  283. WScript.Echo "Failed: " & failed
  284. If failed > 0 Then
  285. WScript.Quit 1
  286. End If
  287. Function RunExportInkjetScenario(ByVal testKitID, ByVal sortDirection, ByVal scenarioName)
  288. RunExportInkjetScenario = ""
  289. InkjetExportSortDirection = sortDirection
  290. Dim scenarioExportDir : scenarioExportDir = fso.BuildPath(scriptDir, "export-test-output-" & LCase(scenarioName))
  291. Dim originalExportDirectory : originalExportDirectory = ExportDirectory
  292. ExportDirectory = scenarioExportDir & "\"
  293. On Error Resume Next
  294. If fso.FolderExists(scenarioExportDir) Then fso.DeleteFolder scenarioExportDir, True
  295. On Error GoTo 0
  296. fso.CreateFolder scenarioExportDir
  297. On Error Resume Next
  298. ExportInkjetFile testKitID
  299. Dim exportErr : exportErr = Err.Number
  300. Dim exportDesc : exportDesc = Err.Description
  301. On Error GoTo 0
  302. If exportErr <> 0 Then
  303. WScript.Echo "FAIL: [INT] ExportInkjetFile " & scenarioName & " error " & exportErr & " - " & exportDesc
  304. failed = failed + 1
  305. ExportDirectory = originalExportDirectory
  306. InkjetExportSortDirection = ""
  307. Exit Function
  308. End If
  309. Dim exportSubfolders : Set exportSubfolders = fso.GetFolder(scenarioExportDir).SubFolders
  310. Dim csvFound : csvFound = False
  311. Dim csvPath : csvPath = ""
  312. Dim sf
  313. For Each sf In exportSubfolders
  314. Dim csvFiles : Set csvFiles = sf.Files
  315. Dim f
  316. For Each f In csvFiles
  317. If LCase(fso.GetExtensionName(f.Name)) = "csv" Then
  318. csvFound = True
  319. csvPath = f.Path
  320. End If
  321. Next
  322. Next
  323. AssertEqual csvFound, True, "[INT] ExportInkjetFile " & scenarioName & ": CSV file created"
  324. If csvFound Then RunExportInkjetScenario = csvPath
  325. ExportDirectory = originalExportDirectory
  326. InkjetExportSortDirection = ""
  327. End Function
  328. Sub AssertExportInkjetCsv(ByVal testKitID, ByVal csvPath, ByVal expectedRows, ByVal testJCode, ByVal scenarioName)
  329. Dim verifyCsv : Set verifyCsv = CreateObject("Chilkat_9_5_0.Csv")
  330. verifyCsv.HasColumnNames = 1
  331. Dim csvLoaded : csvLoaded = verifyCsv.LoadFile(csvPath)
  332. AssertEqual csvLoaded, 1, "[INT] ExportInkjetFile " & scenarioName & ": CSV loaded by Chilkat"
  333. If csvLoaded Then
  334. AssertEqual verifyCsv.NumColumns, 22, "[INT] ExportInkjetFile " & scenarioName & ": 22 columns"
  335. AssertEqual verifyCsv.GetColumnName(0), "Full Name", "[INT] ExportInkjetFile " & scenarioName & ": col 0 = Full Name"
  336. AssertEqual verifyCsv.GetColumnName(5), "IM barcode Characters", "[INT] ExportInkjetFile " & scenarioName & ": col 5 = IM barcode Characters"
  337. AssertEqual verifyCsv.GetColumnName(8), "Ballot Number", "[INT] ExportInkjetFile " & scenarioName & ": col 8 = Ballot Number"
  338. AssertEqual verifyCsv.GetColumnName(11), "Combined Pct_Ballot Num", "[INT] ExportInkjetFile " & scenarioName & ": col 11 = Combined Pct_Ballot Num"
  339. AssertEqual verifyCsv.GetColumnName(19), "Matching Code", "[INT] ExportInkjetFile " & scenarioName & ": col 19 = Matching Code"
  340. AssertEqual verifyCsv.GetColumnName(20), "ColorFilepath", "[INT] ExportInkjetFile " & scenarioName & ": col 20 = ColorFilepath"
  341. AssertEqual verifyCsv.GetColumnName(21), "ColorName", "[INT] ExportInkjetFile " & scenarioName & ": col 21 = ColorName"
  342. AssertEqual verifyCsv.NumRows, expectedRows, "[INT] ExportInkjetFile " & scenarioName & ": row count matches InkjetRecords"
  343. oConn.Open ConnectionString
  344. Dim expectedRs
  345. Set expectedRs = oConn.Execute( _
  346. "SELECT PRECINCT, BALLOT_NUMBER FROM InkjetRecords WHERE KitID=" & testKitID & " " & _
  347. "ORDER BY Val(PRECINCT) " & scenarioName & ", PRECINCT " & scenarioName & ", " & _
  348. "Val(Right(BALLOT_NUMBER, 4)) " & scenarioName & ", Right(BALLOT_NUMBER, 4) " & scenarioName & ";")
  349. Dim checkRows : checkRows = 10
  350. If verifyCsv.NumRows < 10 Then checkRows = verifyCsv.NumRows
  351. Dim r
  352. For r = 0 To checkRows - 1
  353. If expectedRs.EOF Then Exit For
  354. Dim actualPrecinct : actualPrecinct = verifyCsv.GetCell(r, 6)
  355. Dim actualBallotNum : actualBallotNum = verifyCsv.GetCell(r, 8)
  356. Dim actualMatchCode : actualMatchCode = verifyCsv.GetCell(r, 19)
  357. Dim expectedPrecinct : expectedPrecinct = CleanNull(expectedRs("PRECINCT").Value)
  358. Dim expectedBallotNum : expectedBallotNum = TrimLeadingZeros(CleanNull(expectedRs("BALLOT_NUMBER").Value))
  359. AssertEqual (Left(actualBallotNum, 1) <> "0" Or actualBallotNum = ""), True, "[INT] ExportInkjetFile " & scenarioName & ": row " & r & " Ballot Number no leading zeros"
  360. AssertEqual Left(actualMatchCode, Len(testJCode)), testJCode, "[INT] ExportInkjetFile " & scenarioName & ": row " & r & " Matching Code starts with JCode"
  361. AssertEqual actualPrecinct, expectedPrecinct, "[INT] ExportInkjetFile " & scenarioName & ": row " & r & " precinct order"
  362. AssertEqual actualBallotNum, expectedBallotNum, "[INT] ExportInkjetFile " & scenarioName & ": row " & r & " ballot order"
  363. expectedRs.MoveNext
  364. Next
  365. expectedRs.Close
  366. oConn.Close
  367. End If
  368. Set verifyCsv = Nothing
  369. End Sub
  370. Sub LoadFunctions(ByVal filePath, ByVal names)
  371. Dim fileText, lines, i, line
  372. Dim capturing: capturing = False
  373. Dim endKeyword: endKeyword = ""
  374. Dim block: block = ""
  375. If Not fso.FileExists(filePath) Then
  376. WScript.Echo "FAIL: Source file not found: " & filePath
  377. WScript.Quit 1
  378. End If
  379. With fso.OpenTextFile(filePath, ForReading, False, TristateTrue)
  380. fileText = .ReadAll
  381. .Close
  382. End With
  383. ' Normalize line endings and remove nulls/BOM that can appear in UTF-16 reads
  384. fileText = Replace(fileText, ChrW(&HFEFF), "")
  385. fileText = Replace(fileText, Chr(0), "")
  386. fileText = Replace(fileText, vbTab, " ")
  387. fileText = Replace(fileText, vbCrLf, vbLf)
  388. fileText = Replace(fileText, vbCr, vbLf)
  389. lines = Split(fileText, vbLf)
  390. For i = 0 To UBound(lines)
  391. line = lines(i)
  392. If Not capturing Then
  393. Dim nameIndex
  394. For nameIndex = 0 To UBound(names)
  395. Dim kind
  396. If TryStartLine(line, names(nameIndex), kind) Then
  397. capturing = True
  398. endKeyword = "End " & kind
  399. block = block & line & vbCrLf
  400. Exit For
  401. End If
  402. Next
  403. Else
  404. block = block & line & vbCrLf
  405. If LCase(Trim(line)) = LCase(endKeyword) Then
  406. capturing = False
  407. block = block & vbCrLf
  408. End If
  409. End If
  410. Next
  411. If Len(block) = 0 Then
  412. ' Fallback: simple text scan for each function/sub
  413. Dim nameIndex2
  414. For nameIndex2 = 0 To UBound(names)
  415. Dim extracted
  416. extracted = ExtractBlock(fileText, names(nameIndex2))
  417. If Len(extracted) > 0 Then
  418. block = block & extracted & vbCrLf & vbCrLf
  419. End If
  420. Next
  421. End If
  422. If Len(block) = 0 Then
  423. WScript.Echo "FAIL: No functions loaded from " & filePath
  424. WScript.Echo "Debug: file length=" & Len(fileText)
  425. WScript.Quit 1
  426. End If
  427. ExecuteGlobal block
  428. End Sub
  429. Function ExtractBlock(ByVal fileText, ByVal name)
  430. Dim lowerText, lowerName, startPos, endPos, kind, endToken
  431. lowerText = LCase(fileText)
  432. lowerName = LCase(name)
  433. startPos = FindDeclPos(lowerText, lowerName, "function")
  434. kind = "Function"
  435. If startPos = 0 Then
  436. startPos = FindDeclPos(lowerText, lowerName, "sub")
  437. kind = "Sub"
  438. End If
  439. If startPos = 0 Then
  440. ExtractBlock = ""
  441. Exit Function
  442. End If
  443. endToken = "end " & LCase(kind)
  444. endPos = InStr(startPos, lowerText, endToken)
  445. If endPos = 0 Then
  446. ExtractBlock = ""
  447. Exit Function
  448. End If
  449. endPos = endPos + Len(endToken) - 1
  450. ExtractBlock = Mid(fileText, startPos, endPos - startPos + 1)
  451. End Function
  452. Function FindDeclPos(ByVal lowerText, ByVal lowerName, ByVal keyword)
  453. Dim pos, idx, ch, nameLen, nextChar
  454. nameLen = Len(lowerName)
  455. pos = InStr(1, lowerText, keyword)
  456. Do While pos > 0
  457. idx = pos + Len(keyword)
  458. Do While idx <= Len(lowerText)
  459. ch = Mid(lowerText, idx, 1)
  460. If IsWs(ch) Then
  461. idx = idx + 1
  462. Else
  463. Exit Do
  464. End If
  465. Loop
  466. If LCase(Mid(lowerText, idx, nameLen)) = lowerName Then
  467. nextChar = Mid(lowerText, idx + nameLen, 1)
  468. If nextChar = "" Or Not IsNameChar(nextChar) Then
  469. FindDeclPos = pos
  470. Exit Function
  471. End If
  472. End If
  473. pos = InStr(pos + 1, lowerText, keyword)
  474. Loop
  475. FindDeclPos = 0
  476. End Function
  477. Function IsWs(ByVal ch)
  478. IsWs = (ch = " " Or ch = vbTab Or ch = vbLf Or ch = vbCr Or AscW(ch) = 160)
  479. End Function
  480. Function IsNameChar(ByVal ch)
  481. Dim code
  482. code = AscW(ch)
  483. IsNameChar = (code >= 48 And code <= 57) Or (code >= 65 And code <= 90) Or (code >= 97 And code <= 122) Or ch = "_"
  484. End Function
  485. Function TryStartLine(ByVal line, ByVal name, ByRef kind)
  486. Dim lowerLine, lowerName, pos
  487. lowerLine = LCase(line)
  488. lowerName = LCase(name)
  489. pos = FindDeclPos(lowerLine, lowerName, "function")
  490. If pos > 0 Then
  491. kind = "Function"
  492. TryStartLine = True
  493. Exit Function
  494. End If
  495. pos = FindDeclPos(lowerLine, lowerName, "sub")
  496. If pos > 0 Then
  497. kind = "Sub"
  498. TryStartLine = True
  499. Exit Function
  500. End If
  501. TryStartLine = False
  502. End Function
  503. Sub AssertEqual(ByVal actual, ByVal expected, ByVal testName)
  504. If actual = expected Then
  505. passed = passed + 1
  506. WScript.Echo "PASS: " & testName
  507. Else
  508. failed = failed + 1
  509. WScript.Echo "FAIL: " & testName & " | expected=" & FormatValue(expected) & " actual=" & FormatValue(actual)
  510. End If
  511. End Sub
  512. Sub AssertArrayEqual(ByVal actual, ByVal expected, ByVal testName)
  513. Dim ok: ok = True
  514. Dim i
  515. If (UBound(actual) <> UBound(expected)) Then
  516. ok = False
  517. Else
  518. For i = 0 To UBound(actual)
  519. If actual(i) <> expected(i) Then
  520. ok = False
  521. Exit For
  522. End If
  523. Next
  524. End If
  525. If ok Then
  526. passed = passed + 1
  527. WScript.Echo "PASS: " & testName
  528. Else
  529. failed = failed + 1
  530. WScript.Echo "FAIL: " & testName & " | expected=" & ArrayToString(expected) & " actual=" & ArrayToString(actual)
  531. End If
  532. End Sub
  533. Function ArrayToString(ByVal arr)
  534. Dim i, s
  535. s = "["
  536. For i = 0 To UBound(arr)
  537. If i > 0 Then s = s & ", "
  538. s = s & FormatValue(arr(i))
  539. Next
  540. s = s & "]"
  541. ArrayToString = s
  542. End Function
  543. Function FormatValue(ByVal v)
  544. If IsNull(v) Then
  545. FormatValue = "<null>"
  546. ElseIf IsObject(v) Then
  547. FormatValue = "<object>"
  548. ElseIf IsArray(v) Then
  549. FormatValue = "<array>"
  550. Else
  551. FormatValue = Chr(34) & CStr(v) & Chr(34)
  552. End If
  553. End Function
  554. Function LoadChilkatSerial(ByVal filePath)
  555. LoadChilkatSerial = ""
  556. If Not fso.FileExists(filePath) Then
  557. Exit Function
  558. End If
  559. Dim serialFile
  560. Set serialFile = fso.OpenTextFile(filePath, ForReading, False, TristateFalse)
  561. LoadChilkatSerial = Trim(serialFile.ReadAll)
  562. serialFile.Close
  563. Set serialFile = Nothing
  564. End Function

Powered by TurnKey Linux.