Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Araq
2018-01-11 18:05:26 +01:00
19 changed files with 302 additions and 113 deletions

View File

@@ -1202,18 +1202,30 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
# we skip this step here:
if not p.module.compileToCpp:
if handleConstExpr(p, e, d): return
var tmp: TLoc
var t = e.typ.skipTypes(abstractInst)
getTemp(p, t, tmp)
let isRef = t.kind == tyRef
var r = rdLoc(tmp)
if isRef:
rawGenNew(p, tmp, nil)
t = t.lastSon.skipTypes(abstractInst)
r = "(*$1)" % [r]
gcUsage(e)
# check if we need to construct the object in a temporary
var useTemp =
isRef or
(d.k notin {locTemp,locLocalVar,locGlobalVar,locParam,locField}) or
(isPartOf(d.lode, e) != arNo)
var tmp: TLoc
var r: Rope
if useTemp:
getTemp(p, t, tmp)
r = rdLoc(tmp)
if isRef:
rawGenNew(p, tmp, nil)
t = t.lastSon.skipTypes(abstractInst)
r = "(*$1)" % [r]
gcUsage(e)
else:
constructLoc(p, tmp)
else:
constructLoc(p, tmp)
resetLoc(p, d)
r = rdLoc(d)
discard getTypeDesc(p.module, t)
let ty = getUniqueType(t)
for i in 1 ..< e.len:
@@ -1227,15 +1239,19 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
genFieldCheck(p, it.sons[2], r, field)
add(tmp2.r, ".")
add(tmp2.r, field.loc.r)
tmp2.k = locTemp
if useTemp:
tmp2.k = locTemp
tmp2.storage = if isRef: OnHeap else: OnStack
else:
tmp2.k = d.k
tmp2.storage = if isRef: OnHeap else: d.storage
tmp2.lode = it.sons[1]
tmp2.storage = if isRef: OnHeap else: OnStack
expr(p, it.sons[1], tmp2)
if d.k == locNone:
d = tmp
else:
genAssignment(p, d, tmp, {})
if useTemp:
if d.k == locNone:
d = tmp
else:
genAssignment(p, d, tmp, {})
proc lhsDoesAlias(a, b: PNode): bool =
for y in b:

View File

@@ -70,7 +70,7 @@ __clang__
#if defined(_MSC_VER)
# pragma warning(disable: 4005 4100 4101 4189 4191 4200 4244 4293 4296 4309)
# pragma warning(disable: 4310 4365 4456 4477 4514 4574 4611 4668 4702 4706)
# pragma warning(disable: 4710 4711 4774 4800 4820 4996 4090 4297)
# pragma warning(disable: 4710 4711 4774 4800 4809 4820 4996 4090 4297)
#endif
/* ------------------------------------------------------------------------- */

View File

@@ -324,12 +324,12 @@ proc mget*[T](future: FutureVar[T]): var T =
## Future has not been finished.
result = Future[T](future).value
proc finished*[T](future: Future[T] | FutureVar[T]): bool =
proc finished*(future: FutureBase | FutureVar): bool =
## Determines whether ``future`` has completed.
##
## ``True`` may indicate an error or a value. Use ``failed`` to distinguish.
when future is FutureVar[T]:
result = (Future[T](future)).finished
when future is FutureVar:
result = (FutureBase(future)).finished
else:
result = future.finished

View File

@@ -32,6 +32,12 @@ template createCb(retFutureSym, iteratorNameSym,
try:
if not nameIterVar.finished:
var next = nameIterVar()
# Continue while the yielded future is already finished.
while (not next.isNil) and next.finished:
next = nameIterVar()
if nameIterVar.finished:
break
if next == nil:
if not retFutureSym.finished:
let msg = "Async procedure ($1) yielded `nil`, are you await'ing a " &

View File

@@ -413,7 +413,7 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} =
when defineSsl:
CRYPTO_malloc_init()
SslLibraryInit()
doAssert SslLibraryInit() == 1
SslLoadErrorStrings()
ErrLoadBioStrings()
OpenSSL_add_all_algorithms()

View File

@@ -672,7 +672,10 @@ template walkCommon(pattern: string, filter) =
if dotPos < 0 or idx >= ff.len or ff[idx] == '.' or
pattern[dotPos+1] == '*':
yield splitFile(pattern).dir / extractFilename(ff)
if findNextFile(res, f) == 0'i32: break
if findNextFile(res, f) == 0'i32:
let errCode = getLastError()
if errCode == ERROR_NO_MORE_FILES: break
else: raiseOSError(errCode.OSErrorCode)
else: # here we use glob
var
f: Glob
@@ -782,7 +785,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
let xx = if relative: extractFilename(getFilename(f))
else: dir / extractFilename(getFilename(f))
yield (k, xx)
if findNextFile(h, f) == 0'i32: break
if findNextFile(h, f) == 0'i32:
let errCode = getLastError()
if errCode == ERROR_NO_MORE_FILES: break
else: raiseOSError(errCode.OSErrorCode)
else:
var d = opendir(dir)
if d != nil:

View File

@@ -129,8 +129,8 @@ type
## The ``times`` module only supplies implementations for the systems local time and UTC.
## The members ``zoneInfoFromUtc`` and ``zoneInfoFromTz`` should not be accessed directly
## and are only exported so that ``Timezone`` can be implemented by other modules.
zoneInfoFromUtc*: proc (time: Time): ZonedTime {.nimcall, tags: [], raises: [], benign .}
zoneInfoFromTz*: proc (adjTime: Time): ZonedTime {.nimcall, tags: [], raises: [], benign .}
zoneInfoFromUtc*: proc (time: Time): ZonedTime {.tags: [], raises: [], benign.}
zoneInfoFromTz*: proc (adjTime: Time): ZonedTime {.tags: [], raises: [], benign.}
name*: string ## The name of the timezone, f.ex 'Europe/Stockholm' or 'Etc/UTC'. Used for checking equality.
## Se also: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ZonedTime* = object ## Represents a zooned instant in time that is not associated with any calendar.

View File

@@ -406,7 +406,8 @@ proc setStdIoUnbuffered() =
when declared(stdout):
proc echoBinSafe(args: openArray[string]) {.compilerProc.} =
when not defined(windows):
# flockfile deadlocks some versions of Android 5.x.x
when not defined(windows) and not defined(android):
proc flockfile(f: File) {.importc, noDecl.}
proc funlockfile(f: File) {.importc, noDecl.}
flockfile(stdout)
@@ -415,7 +416,7 @@ when declared(stdout):
const linefeed = "\n" # can be 1 or more chars
discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
discard c_fflush(stdout)
when not defined(windows):
when not defined(windows) and not defined(android):
funlockfile(stdout)
{.pop.}

View File

@@ -386,8 +386,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
kdigits, fdigits = 0
exponent: int
integer: uint64
fraction: uint64
frac_exponent= 0
frac_exponent = 0
exp_sign = 1
first_digit = -1
has_sign = false
@@ -480,7 +479,8 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
# if integer is representable in 53 bits: fast path
# max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits)
if kdigits + fdigits <= 16 and first_digit <= 8:
let digits = kdigits + fdigits
if digits <= 15 or (digits <= 16 and first_digit <= 8):
# max float power of ten with set bits above the 53th bit is 10^22
if abs_exponent <= 22:
if exp_negative:
@@ -504,6 +504,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
result = i - start
i = start
# re-parse without error checking, any error should be handled by the code above.
if s[i] == '.': i.inc
while s[i] in {'0'..'9','+','-'}:
if ti < maxlen:
t[ti] = s[i]; inc(ti)

View File

@@ -686,6 +686,7 @@ const
ERROR_FILE_NOT_FOUND* = 2
ERROR_PATH_NOT_FOUND* = 3
ERROR_ACCESS_DENIED* = 5
ERROR_NO_MORE_FILES* = 18
ERROR_HANDLE_EOF* = 38
ERROR_BAD_ARGUMENTS* = 165

View File

@@ -8,6 +8,17 @@
#
## OpenSSL support
##
## When OpenSSL is dynamically linked, the wrapper provides partial forward and backward
## compatibility for OpenSSL versions above and below 1.1.0
##
## OpenSSL can be also statically linked using dynlibOverride:ssl for OpenSSL >= 1.1.0
##
## Build and test examples:
##
## .. code-block::
## ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim
## ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passL:-lcrypto --passL:-lssl -r tests/untestable/tssl.nim
{.deadCodeElim: on.}
@@ -25,8 +36,8 @@ when useWinVersion:
from winlean import SocketHandle
else:
const
versions = "(|.38|.39|.41|.43|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
const versions = "(.1.1|.38|.39|.41|.43|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
when defined(macosx):
const
DLLSSLName = "libssl" & versions & ".dylib"
@@ -140,6 +151,7 @@ const
SSL_OP_NO_SSLv2* = 0x01000000
SSL_OP_NO_SSLv3* = 0x02000000
SSL_OP_NO_TLSv1* = 0x04000000
SSL_OP_NO_TLSv1_1* = 0x08000000
SSL_OP_ALL* = 0x000FFFFF
SSL_VERIFY_NONE* = 0x00000000
SSL_VERIFY_PEER* = 0x00000001
@@ -191,16 +203,39 @@ const
proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
when compileOption("dynlibOverride", "ssl"):
proc SSL_library_init*(): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.}
proc SSL_load_error_strings*() {.cdecl, dynlib: DLLSSLName, importc.}
proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
# TLS_method(), TLS_server_method(), TLS_client_method() are introduced in 1.1.0
# and support SSLv3, TLSv1, TLSv1.1 and TLSv1.2
# SSLv23_method(), SSLv23_server_method(), SSLv23_client_method() are removed in 1.1.0
proc SSLv23_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
when compileOption("dynlibOverride", "ssl"):
# Static linking
proc OPENSSL_init_ssl*(opts: uint64, settings: uint8): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.}
proc SSL_library_init*(): cint {.discardable.} =
## Initialize SSL using OPENSSL_init_ssl for OpenSSL >= 1.1.0
return OPENSSL_init_ssl(0.uint64, 0.uint8)
proc TLS_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
proc SSLv23_method*(): PSSL_METHOD =
TLS_method()
proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
proc SSLv2_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
proc SSLv3_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
template OpenSSL_add_all_algorithms*() = discard
proc OpenSSL_version_num(): culong {.cdecl, dynlib: DLLSSLName, importc.}
proc getOpenSSLVersion*(): culong =
## Return OpenSSL version as unsigned long
OpenSSL_version_num()
proc SSL_load_error_strings*() =
## Removed from OpenSSL 1.1.0
# This proc prevents breaking existing code calling SslLoadErrorStrings
# Static linking against OpenSSL < 1.1.0 is not supported
discard
else:
# Here we're trying to stay compatible with openssl 1.0.* and 1.1.*. Some
# symbols are loaded dynamically and we don't use them if not found.
@@ -223,38 +258,58 @@ else:
if not dl.isNil:
result = symAddr(dl, name)
proc loadPSSLMethod(method1, method2: string): PSSL_METHOD =
## Load <method1> from OpenSSL if available, otherwise <method2>
let m1 = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method1))
if not m1.isNil:
return m1()
cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method2))()
proc SSL_library_init*(): cint {.discardable.} =
let theProc = cast[proc(): cint {.cdecl.}](sslSym("SSL_library_init"))
if not theProc.isNil: result = theProc()
## Initialize SSL using OPENSSL_init_ssl for OpenSSL >= 1.1.0 otherwise
## SSL_library_init
let theProc = cast[proc(opts: uint64, settings: uint8): cint {.cdecl.}](sslSym("OPENSSL_init_ssl"))
if not theProc.isNil:
return theProc(0, 0)
let olderProc = cast[proc(): cint {.cdecl.}](sslSym("SSL_library_init"))
if not olderProc.isNil: result = olderProc()
proc SSL_load_error_strings*() =
let theProc = cast[proc() {.cdecl.}](sslSym("SSL_load_error_strings"))
if not theProc.isNil: theProc()
proc SSLv23_client_method*(): PSSL_METHOD =
let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv23_client_method"))
if not theProc.isNil: result = theProc()
else: result = TLSv1_method()
loadPSSLMethod("SSLv23_client_method", "TLS_client_method")
proc SSLv23_method*(): PSSL_METHOD =
let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv23_method"))
if not theProc.isNil: result = theProc()
else: result = TLSv1_method()
loadPSSLMethod("SSLv23_method", "TLS_method")
proc SSLv2_method*(): PSSL_METHOD =
let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv2_method"))
if not theProc.isNil: result = theProc()
else: result = TLSv1_method()
loadPSSLMethod("SSLv2_method", "TLS_method")
proc SSLv3_method*(): PSSL_METHOD =
let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv3_method"))
if not theProc.isNil: result = theProc()
else: result = TLSv1_method()
loadPSSLMethod("SSLv3_method", "TLS_method")
proc TLS_method*(): PSSL_METHOD =
loadPSSLMethod("TLS_method", "SSLv23_method")
proc TLS_client_method*(): PSSL_METHOD =
loadPSSLMethod("TLS_client_method", "SSLv23_client_method")
proc TLS_server_method*(): PSSL_METHOD =
loadPSSLMethod("TLS_server_method", "SSLv23_server_method")
proc OpenSSL_add_all_algorithms*() =
let theProc = cast[proc() {.cdecl.}](sslSym("OPENSSL_add_all_algorithms_conf"))
if not theProc.isNil: theProc()
proc getOpenSSLVersion*(): culong =
## Return OpenSSL version as unsigned long or 0 if not available
let theProc = cast[proc(): culong {.cdecl.}](sslSym("OpenSSL_version_num"))
result =
if theProc.isNil: 0.culong
else: theProc()
proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.}
proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.}

15
tests/async/t6100.nim Normal file
View File

@@ -0,0 +1,15 @@
discard """
file: "t6100.nim"
exitcode: 0
output: "10000000"
"""
import asyncdispatch
let done = newFuture[int]()
done.complete(1)
proc asyncSum: Future[int] {.async.} =
for _ in 1..10_000_000:
result += await done
echo waitFor asyncSum()

View File

@@ -1,61 +1,7 @@
discard """
exitcode: 0
disabled: "windows"
output: '''
b failure
Async traceback:
tasync_traceback.nim(97) tasync_traceback
asyncmacro.nim(395) a
asyncmacro.nim(34) a_continue
## Resumes an async procedure
tasync_traceback.nim(95) aIter
asyncmacro.nim(395) b
asyncmacro.nim(34) b_continue
## Resumes an async procedure
tasync_traceback.nim(92) bIter
#[
tasync_traceback.nim(97) tasync_traceback
asyncmacro.nim(395) a
asyncmacro.nim(43) a_continue
## Resumes an async procedure
asyncfutures.nim(211) callback=
asyncfutures.nim(190) addCallback
asyncfutures.nim(53) callSoon
asyncmacro.nim(34) a_continue
## Resumes an async procedure
asyncmacro.nim(0) aIter
asyncfutures.nim(304) read
]#
Exception message: b failure
Exception type:
bar failure
Async traceback:
tasync_traceback.nim(113) tasync_traceback
asyncdispatch.nim(1492) waitFor
asyncdispatch.nim(1496) poll
## Processes asynchronous completion events
asyncdispatch.nim(1262) runOnce
asyncdispatch.nim(183) processPendingCallbacks
## Executes pending callbacks
asyncmacro.nim(34) bar_continue
## Resumes an async procedure
tasync_traceback.nim(108) barIter
#[
tasync_traceback.nim(113) tasync_traceback
asyncdispatch.nim(1492) waitFor
asyncdispatch.nim(1496) poll
## Processes asynchronous completion events
asyncdispatch.nim(1262) runOnce
asyncdispatch.nim(183) processPendingCallbacks
## Executes pending callbacks
asyncmacro.nim(34) foo_continue
## Resumes an async procedure
asyncmacro.nim(0) fooIter
asyncfutures.nim(304) read
]#
Exception message: bar failure
Exception type:'''
output: "Matched"
"""
import asyncdispatch
@@ -87,6 +33,8 @@ import asyncdispatch
# tasync_traceback.nim(21) a
# tasync_traceback.nim(18) b
var result = ""
proc b(): Future[int] {.async.} =
if true:
raise newException(OSError, "b failure")
@@ -98,8 +46,8 @@ let aFut = a()
try:
discard waitFor aFut
except Exception as exc:
echo exc.msg
echo()
result.add(exc.msg & "\n")
result.add("\n")
# From #6803
proc bar(): Future[string] {.async.} =
@@ -110,7 +58,69 @@ proc bar(): Future[string] {.async.} =
proc foo(): Future[string] {.async.} = return await bar()
try:
echo waitFor(foo())
result.add(waitFor(foo()) & "\n")
except Exception as exc:
echo exc.msg
echo()
result.add(exc.msg & "\n")
result.add("\n")
# Use re to parse the result
import re
const expected = """
b failure
Async traceback:
tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
asyncmacro\.nim\(\d+?\)\s+?a
asyncmacro\.nim\(\d+?\)\s+?a_continue
## Resumes an async procedure
tasync_traceback\.nim\(\d+?\)\s+?aIter
asyncmacro\.nim\(\d+?\)\s+?b
asyncmacro\.nim\(\d+?\)\s+?b_continue
## Resumes an async procedure
tasync_traceback\.nim\(\d+?\)\s+?bIter
#\[
tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
asyncmacro\.nim\(\d+?\)\s+?a
asyncmacro\.nim\(\d+?\)\s+?a_continue
## Resumes an async procedure
asyncmacro\.nim\(\d+?\)\s+?aIter
asyncfutures\.nim\(\d+?\)\s+?read
\]#
Exception message: b failure
Exception type:
bar failure
Async traceback:
tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
asyncdispatch\.nim\(\d+?\)\s+?waitFor
asyncdispatch\.nim\(\d+?\)\s+?poll
## Processes asynchronous completion events
asyncdispatch\.nim\(\d+?\)\s+?runOnce
asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks
## Executes pending callbacks
asyncmacro\.nim\(\d+?\)\s+?bar_continue
## Resumes an async procedure
tasync_traceback\.nim\(\d+?\)\s+?barIter
#\[
tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
asyncdispatch\.nim\(\d+?\)\s+?waitFor
asyncdispatch\.nim\(\d+?\)\s+?poll
## Processes asynchronous completion events
asyncdispatch\.nim\(\d+?\)\s+?runOnce
asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks
## Executes pending callbacks
asyncmacro\.nim\(\d+?\)\s+?foo_continue
## Resumes an async procedure
asyncmacro\.nim\(\d+?\)\s+?fooIter
asyncfutures\.nim\(\d+?\)\s+?read
\]#
Exception message: bar failure
Exception type:
"""
if result.match(re(expected)):
echo("Matched")
else:
echo("Not matched!")
echo()
echo(result)
quit(QuitFailure)

View File

@@ -18,8 +18,8 @@ var fs = newFutureStream[int]()
proc alpha() {.async.} =
for i in 0 .. 5:
await sleepAsync(1000)
await fs.write(i)
await sleepAsync(1000)
echo("Done")
fs.complete()

View File

@@ -48,5 +48,11 @@ doAssert "2.71828182845904523536028747".parseFloat ==
2.71828182845904523536028747
doAssert 0.00097656250000000021684043449710088680149056017398834228515625 ==
"0.00097656250000000021684043449710088680149056017398834228515625".parseFloat
doAssert 0.00998333 == ".00998333".parseFloat
doAssert 0.00128333 == ".00128333".parseFloat
doAssert 999999999999999.0 == "999999999999999.0".parseFloat
doAssert 9999999999999999.0 == "9999999999999999.0".parseFloat
doAssert 0.999999999999999 == ".999999999999999".parseFloat
doAssert 0.9999999999999999 == ".9999999999999999".parseFloat
echo("passed all tests.")

View File

@@ -15,7 +15,8 @@ discard """
(y: 678, x: 123)
(y: 678, x: 123)
(y: 0, x: 123)
(y: 678, x: 123)'''
(y: 678, x: 123)
(y: 123, x: 678)'''
"""
type
@@ -75,3 +76,7 @@ when true:
echo b # (y: 0, x: 123)
b=B(y: 678, x: 123)
echo b # (y: 678, x: 123)
b=B(y: b.x, x: b.y)
echo b # (y: 123, x: 678)
GC_fullCollect()

View File

@@ -1,3 +1,8 @@
discard """
output: '''42
Foo'''
"""
type TFoo{.exportc.} = object
x:int
@@ -48,3 +53,5 @@ type NamedGraphic = object of Graphic2
var ngr = NamedGraphic(kind: Koo, radius: 6.9, name: "Foo")
echo ngr.name
GC_fullCollect()

View File

@@ -281,6 +281,30 @@ suite "ttimes":
test "parseTest":
runTimezoneTests()
test "dynamic timezone":
proc staticOffset(offset: int): Timezone =
proc zoneInfoFromTz(adjTime: Time): ZonedTime =
result.isDst = false
result.utcOffset = offset
result.adjTime = adjTime
proc zoneInfoFromUtc(time: Time): ZonedTime =
result.isDst = false
result.utcOffset = offset
result.adjTime = fromUnix(time.toUnix - offset)
result.name = ""
result.zoneInfoFromTz = zoneInfoFromTz
result.zoneInfoFromUtc = zoneInfoFromUtc
let tz = staticOffset(-9000)
let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz)
check dt.utcOffset == -9000
check dt.isDst == false
check $dt == "2000-01-01T12:00:00+02:30"
check $dt.utc == "2000-01-01T09:30:00+00:00"
check $dt.utc.inZone(tz) == $dt
test "isLeapYear":
check isLeapYear(2016)
check (not isLeapYear(2015))

36
tests/untestable/tssl.nim Normal file
View File

@@ -0,0 +1,36 @@
#
# Nim - SSL integration tests
# (c) Copyright 2017 Nim contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Warning: this test performs external networking.
##
## Test with:
## ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim
## ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passL:-lcrypto --passL:-lssl -r tests/untestable/tssl.nim
## The compilation is expected to succeed with any new/old version of OpenSSL,
## both with dynamic and static linking.
## The "howsmyssl" test is known to fail with OpenSSL < 1.1 due to insecure
## cypher suites being used.
import httpclient, os
from strutils import contains, toHex
from openssl import getOpenSSLVersion
when isMainModule:
echo "version: 0x" & $getOpenSSLVersion().toHex()
let client = newHttpClient()
# hacky SSL check
const url = "https://www.howsmyssl.com"
let report = client.getContent(url)
if not report.contains(">Probably Okay</span>"):
let fn = getTempDir() / "sslreport.html"
echo "SSL CHECK ERROR, see " & fn
writeFile(fn, report)
quit(1)
echo "done"