tenvvars.nim 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. discard """
  2. matrix: "--mm:refc; --mm:orc"
  3. joinable: false
  4. targets: "c js cpp"
  5. """
  6. import std/envvars
  7. from std/sequtils import toSeq
  8. import stdtest/testutils
  9. import std/[assertions]
  10. when not defined(js):
  11. import std/typedthreads
  12. # "LATIN CAPITAL LETTER AE" in UTF-8 (0xc386)
  13. const unicodeUtf8 = "\xc3\x86"
  14. template main =
  15. block: # delEnv, existsEnv, getEnv, envPairs
  16. for val in ["val", "", unicodeUtf8]: # ensures empty val works too
  17. const key = "NIM_TESTS_TOSENV_KEY"
  18. doAssert not existsEnv(key)
  19. putEnv(key, "tempval")
  20. doAssert existsEnv(key)
  21. doAssert getEnv(key) == "tempval"
  22. putEnv(key, val) # change a key that already exists
  23. doAssert existsEnv(key)
  24. doAssert getEnv(key) == val
  25. doAssert (key, val) in toSeq(envPairs())
  26. delEnv(key)
  27. doAssert (key, val) notin toSeq(envPairs())
  28. doAssert not existsEnv(key)
  29. delEnv(key) # deleting an already deleted env var
  30. doAssert not existsEnv(key)
  31. block:
  32. doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == ""
  33. doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " "
  34. doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval"
  35. whenVMorJs: discard # xxx improve
  36. do:
  37. doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE"))
  38. doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE"))
  39. doAssert not existsEnv("")
  40. doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE")
  41. doAssert not existsEnv("NIM_TESTS_TOSENV_PUT")
  42. static: main()
  43. main()
  44. when defined(windows):
  45. import std/widestrs
  46. proc c_wgetenv(env: WideCString): WideCString {.importc: "_wgetenv", header: "<stdlib.h>".}
  47. proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
  48. when not defined(js) and not defined(nimscript):
  49. block: # bug #18533
  50. var thr: Thread[void]
  51. proc threadFunc {.thread.} = putEnv("foo", "fooVal2")
  52. putEnv("foo", "fooVal1")
  53. doAssert getEnv("foo") == "fooVal1"
  54. createThread(thr, threadFunc)
  55. joinThreads(thr)
  56. when defined(windows):
  57. doAssert getEnv("foo") == $c_wgetenv("foo".newWideCString)
  58. else:
  59. doAssert getEnv("foo") == $c_getenv("foo".cstring)
  60. doAssertRaises(OSError): delEnv("foo=bar")
  61. when defined(windows) and not defined(nimscript):
  62. import std/encodings
  63. proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "<stdlib.h>".}
  64. proc c_wputenv(env: WideCString): int32 {.importc: "_wputenv", header: "<stdlib.h>".}
  65. block: # Bug #20083
  66. # These test that `getEnv`, `putEnv` and `existsEnv` handle Unicode
  67. # characters correctly. This means that module X in the process calling the
  68. # CRT environment variable API will get the correct string. Raw CRT API
  69. # calls below represent module X.
  70. # Getting an env. var. with unicode characters returns the correct UTF-8
  71. # encoded string.
  72. block:
  73. const envName = "twin_envvars1"
  74. doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
  75. doAssert existsEnv(envName)
  76. doAssert getEnv(envName) == unicodeUtf8
  77. # Putting an env. var. with unicode characters gives the correct UTF-16
  78. # encoded string from low-level routine.
  79. block:
  80. const envName = "twin_envvars2"
  81. putEnv(envName, unicodeUtf8)
  82. doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
  83. # Env. name containing Unicode characters is retrieved correctly
  84. block:
  85. const envName = unicodeUtf8 & "1"
  86. doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
  87. doAssert existsEnv(envName)
  88. doAssert getEnv(envName) == unicodeUtf8
  89. # Env. name containing Unicode characters is set correctly
  90. block:
  91. const envName = unicodeUtf8 & "2"
  92. putEnv(envName, unicodeUtf8)
  93. doAssert existsEnv(envName)
  94. doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
  95. # Env. name containing Unicode characters and empty value is set correctly
  96. block:
  97. const envName = unicodeUtf8 & "3"
  98. putEnv(envName, "")
  99. doAssert existsEnv(envName)
  100. doAssert $c_wgetenv(envName.newWideCString) == ""
  101. # It's hard to test on Windows code pages, because there is no "change
  102. # a process' locale" API.
  103. if getCurrentEncoding(true) == "windows-1252":
  104. const
  105. unicodeAnsi = "\xc6" # `unicodeUtf8` in `windows-1252` encoding
  106. # Test that env. var. ANSI API has correct encoding
  107. block:
  108. const
  109. envName = unicodeUtf8 & "4"
  110. envNameAnsi = unicodeAnsi & "4"
  111. putEnv(envName, unicodeUtf8)
  112. doAssert $c_getenv(envNameAnsi.cstring) == unicodeAnsi
  113. block:
  114. const
  115. envName = unicodeUtf8 & "5"
  116. envNameAnsi = unicodeAnsi & "5"
  117. doAssert c_putenv((envNameAnsi & "=" & unicodeAnsi).cstring) == 0
  118. doAssert getEnv(envName) == unicodeUtf8
  119. # Env. name containing Unicode characters and empty value is set correctly;
  120. # and, if env. name. characters cannot be represented in codepage, don't
  121. # raise an error.
  122. #
  123. # `win_setenv.nim` converts UTF-16 to ANSI when setting empty env. var. The
  124. # windows-1250 locale has no representation of `abreveUtf8` below, so the
  125. # conversion will fail, but this must not be fatal. It is expected that the
  126. # routine ignores updating MBCS environment (`environ` global) and carries
  127. # on.
  128. block:
  129. const
  130. # "LATIN SMALL LETTER A WITH BREVE" in UTF-8
  131. abreveUtf8 = "\xc4\x83"
  132. envName = abreveUtf8 & "6"
  133. putEnv(envName, "")
  134. doAssert existsEnv(envName)
  135. doAssert $c_wgetenv(envName.newWideCString) == ""
  136. doAssert getEnv(envName) == ""