summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2012-03-31 18:51:11 +0300
committerZahary Karadjov <zahary@gmail.com>2012-03-31 18:51:11 +0300
commit8d698b2bdd63cb7390a418d9ebb3ee7fdc7ea3b5 (patch)
tree3fb011eb742df74754abc2479d211bbdbef16b02 /tests
parent22dc76a361c70af93403dfbf2610c8d49111637c (diff)
parentc7fc519fa39ded59744bc677261faa04b6947cee (diff)
downloadNim-8d698b2bdd63cb7390a418d9ebb3ee7fdc7ea3b5.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod into upstream
Diffstat (limited to 'tests')
-rw-r--r--tests/benchmark.nim47
-rw-r--r--tests/benchmarks/fannkuch.nim69
-rw-r--r--tests/benchmarks/quicksort.nim54
-rw-r--r--tests/compile/tglobalforvar.nim7
-rw-r--r--tests/compile/tircbot.nim447
-rwxr-xr-xtests/reject/t99bott.nim2
-rw-r--r--tests/reject/tenumitems.nim2
7 files changed, 626 insertions, 2 deletions
diff --git a/tests/benchmark.nim b/tests/benchmark.nim
new file mode 100644
index 000000000..8dd9cc2e2
--- /dev/null
+++ b/tests/benchmark.nim
@@ -0,0 +1,47 @@
+#
+#
+#            Nimrod Benchmark tool
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This program runs benchmarks
+import osproc, os, times, json
+
+type
+  TBenchResult = tuple[file: string, success: bool, time: float]
+
+proc compileBench(file: string) =
+  ## Compiles ``file``.
+  doAssert(execCmdEx("nimrod c -d:release " & file).exitCode == QuitSuccess)
+
+proc runBench(file: string): TBenchResult =
+  ## Runs ``file`` and returns info on how long it took to run.
+  var start = epochTime()
+  if execCmdEx(file.addFileExt(ExeExt)).exitCode == QuitSuccess:
+    var t = epochTime() - start
+    result = (file, true, t)
+  else: result = (file, false, -1.0)
+
+proc genOutput(benches: seq[TBenchResult]): PJsonNode =
+  result = newJObject()
+  for i in benches:
+    if i.success:
+      result[i.file.extractFilename] = newJFloat(i.time)
+    else:
+      result[i.file.extractFilename] = newJNull()
+
+proc doBench(): seq[TBenchResult] =
+  result = @[]
+  for i in walkFiles("tests/benchmarks/*.nim"):
+    echo(i.extractFilename)
+    compileBench(i)
+    result.add(runBench(i))
+
+when isMainModule:
+  var b = doBench()
+  var output = genOutput(b)
+  writeFile("benchmarkResults.json", pretty(output))
+  
\ No newline at end of file
diff --git a/tests/benchmarks/fannkuch.nim b/tests/benchmarks/fannkuch.nim
new file mode 100644
index 000000000..15f78f50c
--- /dev/null
+++ b/tests/benchmarks/fannkuch.nim
@@ -0,0 +1,69 @@
+import os
+import strutils
+
+proc fannkuch (n: int): int =
+    var 
+        count: seq[int]
+        maxFlips = 0
+        m        = n-1
+        r        = n
+        check    = 0
+        perm1: seq[int]
+        perm:  seq[int]
+
+    newSeq (count, n+1)
+    newSeq (perm1, n)
+    newSeq (perm, n)
+    for i in 0 .. n-1:
+        count[i] = i+1
+        perm1[i] = i
+        perm[i]  = i
+    count[n] = n+1
+
+    while True:
+        if check < 30:
+            for i in items (perm1):
+                write (stdout, $(i+1))
+            echo ("")
+            inc (check)
+
+        while r != 1:
+            count[r-1] = r
+            dec (r)
+
+        if perm1[0] != 0 and perm1[m] != m:
+            # perm = perm1
+            # The above line is between 3 and 4 times slower than the loop below!
+            for i in 0 .. n-1:
+                perm[i] = perm1[i]
+            var flipsCount = 0
+            var k = perm[0]
+            while k != 0:
+                for i in 0 .. (k div 2):
+                    swap (perm[i], perm[k-i])
+                inc (flipsCount)
+                k = perm[0]
+
+            if flipsCount > maxFlips:
+                maxFlips = flipsCount
+
+        block makePerm:
+            while r != n:
+                var tmp = perm1[0]
+                # # perm1.delete (0)
+                # # perm1.insert (tmp, r)
+                # # The above is about twice as slow as the following:
+                # moveMem (addr (perm1[0]), addr (perm1[1]), r * sizeof (int))
+                # The call to moveMem is about 50% slower than the loop below!
+                for i in 0 .. r-1:
+                    perm1[i] = perm1[i+1]
+                perm1[r] = tmp
+                
+                dec (count[r])
+                if count[r] > 0:
+                    break makePerm
+                inc (r)
+            return maxFlips
+
+var n = 10
+echo ("Pfannkuchen(" & $n & ") = " & $fannkuch (n))
\ No newline at end of file
diff --git a/tests/benchmarks/quicksort.nim b/tests/benchmarks/quicksort.nim
new file mode 100644
index 000000000..599e3674c
--- /dev/null
+++ b/tests/benchmarks/quicksort.nim
@@ -0,0 +1,54 @@
+import os
+import strutils
+
+# Generate some pseudo-random data
+var seed: tuple[s1, s2, s3: int32] = (2'i32, 8'i32, 16'i32)
+
+proc random(): int32 =
+    seed = (((((((seed[0] and 0x0007_FFFF'i32) shl 13'i32) xor seed[0]) shr
+               19'i32) and 0x0000_1FFF'i32) xor
+             ((seed[0] and 0x000F_FFFE'i32) shl 12'i32)),
+
+            ((((((seed[1] and 0x3FFF_FFFF'i32) shl  2'i32) xor seed[1]) shr
+               25'i32) and 0x0000_007F'i32) xor
+             ((seed[1] and 0x0FFF_FFF8'i32) shl  4'i32)),
+
+            ((((((seed[2] and 0x1FFF_FFFF'i32) shl  3'i32) xor seed[2]) shr
+               11'i32) and 0x001F_FFFF'i32) xor
+             ((seed[2] and 0x0000_7FF0'i32) shl 17'i32)))
+    return seed[0] xor seed[1] xor seed[2]
+
+var n = 9999999
+
+var data: seq[int32]
+newSeq (data, n)
+for i in 0 .. data.high():
+    data[i] = random()
+
+
+proc `$` (d: seq[int32]): string =
+    result = "[ "
+    for i in items (d):
+        result.addSep (", ", 2)
+        result.add ($(i and 0xFFFF_FFFF'i64))
+    result.add (" ]")
+
+# Sort the data
+proc sort (start, stop: int) =
+    if stop <= start+1:
+        return
+
+    var j = start
+    for i in start..stop-2:
+        if data[i] <% data[stop-1]:
+            swap (data[i], data[j])
+            inc (j)
+    swap (data[j], data[stop-1])
+
+    sort (start, j)
+    sort (j+1, stop)
+
+sort (0, data.len)
+echo (data[n div 2 - 1] and 0xFFFF_FFFF'i64, ", ",
+      data[n div 2] and 0xFFFF_FFFF'i64, ", ",
+      data[n div 2 + 1] and 0xFFFF_FFFF'i64)
\ No newline at end of file
diff --git a/tests/compile/tglobalforvar.nim b/tests/compile/tglobalforvar.nim
new file mode 100644
index 000000000..9f61ebcab
--- /dev/null
+++ b/tests/compile/tglobalforvar.nim
@@ -0,0 +1,7 @@
+
+var funcs: seq[proc (): int] = @[]
+for i in 0..10:
+  funcs.add((proc (): int = return i * i))
+
+echo(funcs[3]())
+
diff --git a/tests/compile/tircbot.nim b/tests/compile/tircbot.nim
new file mode 100644
index 000000000..91be18092
--- /dev/null
+++ b/tests/compile/tircbot.nim
@@ -0,0 +1,447 @@
+import irc, sockets, asyncio, json, os, strutils, times, redis
+
+type
+  TDb* = object
+    r*: TRedis
+    lastPing: float
+
+  TBuildResult* = enum
+    bUnknown, bFail, bSuccess
+
+  TTestResult* = enum
+    tUnknown, tFail, tSuccess
+
+  TEntry* = tuple[c: TCommit, p: seq[TPlatform]]
+  
+  TCommit* = object
+    commitMsg*, username*, hash*: string
+    date*: TTime
+
+  TPlatform* = object
+    buildResult*: TBuildResult
+    testResult*: TTestResult
+    failReason*, platform*: string
+    total*, passed*, skipped*, failed*: biggestInt
+    csources*: bool
+
+const
+  listName = "commits"
+  failOnExisting = False
+
+proc open*(host = "localhost", port: TPort): TDb =
+  result.r = redis.open(host, port)
+  result.lastPing = epochTime()
+
+proc customHSet(database: TDb, name, field, value: string) =
+  if database.r.hSet(name, field, value).int == 0:
+    if failOnExisting:
+      assert(false)
+    else:
+      echo("[Warning:REDIS] ", field, " already exists in ", name)
+
+proc updateProperty*(database: TDb, commitHash, platform, property,
+                    value: string) =
+  var name = platform & ":" & commitHash
+  if database.r.hSet(name, property, value).int == 0:
+    echo("[INFO:REDIS] '$1' field updated in hash" % [property])
+  else:
+    echo("[INFO:REDIS] '$1' new field added to hash" % [property])
+
+proc globalProperty*(database: TDb, commitHash, property, value: string) =
+  if database.r.hSet(commitHash, property, value).int == 0:
+    echo("[INFO:REDIS] '$1' field updated in hash" % [property])
+  else:
+    echo("[INFO:REDIS] '$1' new field added to hash" % [property])
+
+proc addCommit*(database: TDb, commitHash, commitMsg, user: string) =
+  # Add the commit hash to the `commits` list.
+  discard database.r.lPush(listName, commitHash)
+  # Add the commit message, current date and username as a property
+  globalProperty(database, commitHash, "commitMsg", commitMsg)
+  globalProperty(database, commitHash, "date", $int(getTime()))
+  globalProperty(database, commitHash, "username", user)
+
+proc keepAlive*(database: var TDb) =
+  ## Keep the connection alive. Ping redis in this case. This functions does
+  ## not guarantee that redis will be pinged.
+  var t = epochTime()
+  if t - database.lastPing >= 60.0:
+    echo("PING -> redis")
+    assert(database.r.ping() == "PONG")
+    database.lastPing = t
+    
+proc getCommits*(database: TDb,
+                 plStr: var seq[string]): seq[TEntry] =
+  result = @[]
+  var commitsRaw = database.r.lrange("commits", 0, -1)
+  for c in items(commitsRaw):
+    var commit: TCommit
+    commit.hash = c
+    for key, value in database.r.hPairs(c):
+      case normalize(key)
+      of "commitmsg": commit.commitMsg = value
+      of "date": commit.date = TTime(parseInt(value))
+      of "username": commit.username = value
+      else:
+        echo(key)
+        assert(false)
+
+    var platformsRaw = database.r.lrange(c & ":platforms", 0, -1)
+    var platforms: seq[TPlatform] = @[]
+    for p in items(platformsRaw):
+      var platform: TPlatform
+      for key, value in database.r.hPairs(p & ":" & c):
+        case normalize(key)
+        of "buildresult":
+          platform.buildResult = parseInt(value).TBuildResult
+        of "testresult":
+          platform.testResult = parseInt(value).TTestResult
+        of "failreason":
+          platform.failReason = value
+        of "total":
+          platform.total = parseBiggestInt(value)
+        of "passed":
+          platform.passed = parseBiggestInt(value)
+        of "skipped":
+          platform.skipped = parseBiggestInt(value)
+        of "failed":
+          platform.failed = parseBiggestInt(value)
+        of "csources":
+          platform.csources = if value == "t": true else: false
+        else:
+          echo(normalize(key))
+          assert(false)
+      
+      platform.platform = p
+      
+      platforms.add(platform)
+      if p notin plStr:
+        plStr.add(p)
+    result.add((commit, platforms))
+
+proc commitExists*(database: TDb, commit: string, starts = false): bool =
+  # TODO: Consider making the 'commits' list a set.
+  for c in items(database.r.lrange("commits", 0, -1)):
+    if starts:
+      if c.startsWith(commit): return true
+    else:
+      if c == commit: return true
+  return false
+
+proc platformExists*(database: TDb, commit: string, platform: string): bool =
+  for p in items(database.r.lrange(commit & ":" & "platforms", 0, -1)):
+    if p == platform: return true
+
+proc expandHash*(database: TDb, commit: string): string =
+  for c in items(database.r.lrange("commits", 0, -1)):
+    if c.startsWith(commit): return c
+  assert false
+
+proc isNewest*(database: TDb, commit: string): bool =
+  return database.r.lIndex("commits", 0) == commit
+
+proc getNewest*(database: TDb): string =
+  return database.r.lIndex("commits", 0)
+
+proc addPlatform*(database: TDb, commit: string, platform: string) =
+  assert database.commitExists(commit)
+  assert (not database.platformExists(commit, platform))
+  var name = platform & ":" & commit
+  if database.r.exists(name):
+    if failOnExisting: quit("[FAIL] " & name & " already exists!", 1)
+    else: echo("[Warning] " & name & " already exists!")
+
+  discard database.r.lPush(commit & ":" & "platforms", platform)
+
+proc `[]`*(p: seq[TPlatform], name: string): TPlatform =
+  for platform in items(p):
+    if platform.platform == name:
+      return platform
+  raise newException(EInvalidValue, name & " platforms not found in commits.")
+  
+proc contains*(p: seq[TPlatform], s: string): bool =
+  for i in items(p):
+    if i.platform == s:
+      return True
+    
+
+type
+  PState = ref TState
+  TState = object of TObject
+    dispatcher: PDispatcher
+    sock: PAsyncSocket
+    ircClient: PAsyncIRC
+    hubPort: TPort
+    database: TDb
+    dbConnected: bool
+
+  TSeenType = enum
+    PSeenJoin, PSeenPart, PSeenMsg, PSeenNick, PSeenQuit
+  
+  TSeen = object
+    nick: string
+    channel: string
+    timestamp: TTime
+    case kind*: TSeenType
+    of PSeenJoin: nil
+    of PSeenPart, PSeenQuit, PSeenMsg:
+      msg: string
+    of PSeenNick:
+      newNick: string
+
+const
+  ircServer = "irc.freenode.net"
+  joinChans = @["#nimrod"]
+  botNickname = "NimBot"
+
+proc setSeen(d: TDb, s: TSeen) =
+  discard d.r.del("seen:" & s.nick)
+
+  var hashToSet = @[("type", $s.kind.int), ("channel", s.channel),
+                    ("timestamp", $s.timestamp.int)]
+  case s.kind
+  of PSeenJoin: nil
+  of PSeenPart, PSeenMsg, PSeenQuit:
+    hashToSet.add(("msg", s.msg))
+  of PSeenNick:
+    hashToSet.add(("newnick", s.newNick))
+  
+  d.r.hMSet("seen:" & s.nick, hashToSet)
+
+proc getSeen(d: TDb, nick: string, s: var TSeen): bool =
+  if d.r.exists("seen:" & nick):
+    result = true
+    s.nick = nick
+    # Get the type first
+    s.kind = d.r.hGet("seen:" & nick, "type").parseInt.TSeenType
+    
+    for key, value in d.r.hPairs("seen:" & nick):
+      case normalize(key)
+      of "type":
+        #s.kind = value.parseInt.TSeenType
+      of "channel":
+        s.channel = value
+      of "timestamp":
+        s.timestamp = TTime(value.parseInt)
+      of "msg":
+        s.msg = value
+      of "newnick":
+        s.newNick = value
+
+template createSeen(typ: TSeenType, n, c: string): stmt =
+  var seenNick: TSeen
+  seenNick.kind = typ
+  seenNick.nick = n
+  seenNick.channel = c
+  seenNick.timestamp = getTime()
+
+proc parseReply(line: string, expect: string): Bool =
+  var jsonDoc = parseJson(line)
+  return jsonDoc["reply"].str == expect
+
+proc limitCommitMsg(m: string): string =
+  ## Limits the message to 300 chars and adds ellipsis.
+  var m1 = m
+  if NewLines in m1:
+    m1 = m1.splitLines()[0]
+  
+  if m1.len >= 300:
+    m1 = m1[0..300]
+
+  if m1.len >= 300 or NewLines in m: m1.add("... ")
+
+  if NewLines in m: m1.add($m.splitLines().len & " more lines")
+
+  return m1
+
+proc handleWebMessage(state: PState, line: string) =
+  echo("Got message from hub: " & line)
+  var json = parseJson(line)
+  if json.existsKey("payload"):
+    for i in 0..min(4, json["payload"]["commits"].len-1):
+      var commit = json["payload"]["commits"][i]
+      # Create the message
+      var message = ""
+      message.add(json["payload"]["repository"]["owner"]["name"].str & "/" &
+                  json["payload"]["repository"]["name"].str & " ")
+      message.add(commit["id"].str[0..6] & " ")
+      message.add(commit["author"]["name"].str & " ")
+      message.add("[+" & $commit["added"].len & " ")
+      message.add("±" & $commit["modified"].len & " ")
+      message.add("-" & $commit["removed"].len & "]: ")
+      message.add(limitCommitMsg(commit["message"].str))
+
+      # Send message to #nimrod.
+      state.ircClient[].privmsg(joinChans[0], message)
+  elif json.existsKey("redisinfo"):
+    assert json["redisinfo"].existsKey("port")
+    let redisPort = json["redisinfo"]["port"].num
+    state.dbConnected = true
+
+proc hubConnect(state: PState)
+proc handleConnect(s: PAsyncSocket, userArg: PObject) =
+  let state = PState(userArg)
+  try:
+    # Send greeting
+    var obj = newJObject()
+    obj["name"] = newJString("irc")
+    obj["platform"] = newJString("?")
+    state.sock.send($obj & "\c\L")
+
+    # Wait for reply.
+    var line = ""
+    sleep(1500)
+    if state.sock.recvLine(line):
+      assert(line != "")
+      doAssert parseReply(line, "OK")
+      echo("The hub accepted me!")
+    else:
+      raise newException(EInvalidValue,
+                         "Hub didn't accept me. Waited 1.5 seconds.")
+    
+    # ask for the redis info
+    var riobj = newJObject()
+    riobj["do"] = newJString("redisinfo")
+    state.sock.send($riobj & "\c\L")
+    
+  except EOS:
+    echo(getCurrentExceptionMsg())
+    s.close()
+    echo("Waiting 5 seconds...")
+    sleep(5000)
+    state.hubConnect()
+
+proc handleRead(s: PAsyncSocket, userArg: PObject) =
+  let state = PState(userArg)
+  var line = ""
+  if state.sock.recvLine(line):
+    if line != "":
+      # Handle the message
+      state.handleWebMessage(line)
+    else:
+      echo("Disconnected from hub: ", OSErrorMsg())
+      s.close()
+      echo("Reconnecting...")
+      state.hubConnect()
+  else:
+    echo(OSErrorMsg())
+
+proc hubConnect(state: PState) =
+  state.sock = AsyncSocket()
+  state.sock.connect("127.0.0.1", state.hubPort)
+  state.sock.userArg = state
+  state.sock.handleConnect = handleConnect
+  state.sock.handleRead = handleRead
+
+  state.dispatcher.register(state.sock)
+
+proc handleIrc(irc: var TAsyncIRC, event: TIRCEvent, userArg: PObject) =
+  let state = PState(userArg)
+  case event.typ
+  of EvDisconnected:
+    while not state.ircClient[].isConnected:
+      try:
+        state.ircClient.connect()
+      except:
+        echo("Error reconnecting: ", getCurrentExceptionMsg())
+      
+      echo("Waiting 5 seconds...")
+      sleep(5000)
+    echo("Reconnected successfully!")
+  of EvMsg:
+    echo("< ", event.raw)
+    case event.cmd
+    of MPrivMsg:
+      let msg = event.params[event.params.len-1]
+      let words = msg.split(' ')
+      template pm(msg: string): stmt =
+        state.ircClient[].privmsg(event.origin, msg)
+      case words[0]
+      of "!ping": pm("pong")
+      of "!lag":
+        if state.ircClient[].getLag != -1.0:
+          var lag = state.ircClient[].getLag
+          lag = lag * 1000.0
+          pm($int(lag) & "ms between me and the server.")
+        else:
+          pm("Unknown.")
+      of "!seen":
+        if words.len > 1:
+          let nick = words[1]
+          if nick == botNickname:
+            pm("Yes, I see myself.")
+          echo(nick)
+          var seenInfo: TSeen
+          if state.database.getSeen(nick, seenInfo):
+            var mSend = ""
+            case seenInfo.kind
+            of PSeenMsg:
+              pm("$1 was last seen on $2 in $3 saying: $4" %
+                    [seenInfo.nick, $seenInfo.timestamp,
+                     seenInfo.channel, seenInfo.msg])
+            of PSeenJoin:
+              pm("$1 was last seen on $2 joining $3" %
+                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel])
+            of PSeenPart:
+              pm("$1 was last seen on $2 leaving $3 with message: $4" %
+                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel,
+                         seenInfo.msg])
+            of PSeenQuit:
+              pm("$1 was last seen on $2 quitting with message: $3" %
+                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.msg])
+            of PSeenNick:
+              pm("$1 was last seen on $2 changing nick to $3" %
+                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.newNick])
+            
+          else:
+            pm("I have not seen " & nick)
+        else:
+          pm("Syntax: !seen <nick>")
+
+      # TODO: ... commands
+
+      # -- Seen
+      # Log this as activity.
+      createSeen(PSeenMsg, event.nick, event.origin)
+      seenNick.msg = msg
+      state.database.setSeen(seenNick)
+    of MJoin:
+      createSeen(PSeenJoin, event.nick, event.origin)
+      state.database.setSeen(seenNick)
+    of MPart:
+      createSeen(PSeenPart, event.nick, event.origin)
+      let msg = event.params[event.params.high]
+      seenNick.msg = msg
+      state.database.setSeen(seenNick)
+    of MQuit:
+      createSeen(PSeenQuit, event.nick, event.origin)
+      let msg = event.params[event.params.high]
+      seenNick.msg = msg
+      state.database.setSeen(seenNick)
+    of MNick:
+      createSeen(PSeenNick, event.nick, "#nimrod")
+      seenNick.newNick = event.params[0]
+      state.database.setSeen(seenNick)
+    else:
+      nil # TODO: ?
+
+proc open(port: TPort = TPort(5123)): PState =
+  new(result)
+  result.dispatcher = newDispatcher()
+  
+  result.hubPort = port
+  result.hubConnect()
+
+  # Connect to the irc server.
+  result.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
+                 joinChans = joinChans, ircEvent = handleIrc, userArg = result)
+  result.ircClient.connect()
+  result.dispatcher.register(result.ircClient)
+
+  result.dbConnected = false
+
+var state = tircbot.open() # Connect to the website and the IRC server.
+
+while state.dispatcher.poll():
+  if state.dbConnected:
+    state.database.keepAlive()
diff --git a/tests/reject/t99bott.nim b/tests/reject/t99bott.nim
index 7d11ba4b0..7ebfd61e9 100755
--- a/tests/reject/t99bott.nim
+++ b/tests/reject/t99bott.nim
@@ -1,7 +1,7 @@
 discard """
   file: "t99bott.nim"
   line: 26
-  errormsg: "cannot evaluate 'GetBottleNumber(bn)'"
+  errormsg: "constant expression expected"
   disabled: false
 """
 ## 99 Bottles of Beer
diff --git a/tests/reject/tenumitems.nim b/tests/reject/tenumitems.nim
index a0497fd59..b6eee5ba8 100644
--- a/tests/reject/tenumitems.nim
+++ b/tests/reject/tenumitems.nim
@@ -1,6 +1,6 @@
 discard """
   line: 7
-  errormsg: "a type has no value"
+  errormsg: "type mismatch"
 """
 
 type a = enum b,c,d