use System.Reflection use System.Text.RegularExpressions namespace Cobra.Core class CobraCore shared ## Release info get versionDescription as String """ Returns a textual description of the version such as "X.Y.Z" or "svn-post-X.Y.Z". """ return 'svn-post-[.version]' # return .version.toString get isOfficialRelease return false get version as Version return Version(0, 9, 6) get releaseNum as int return 32 ## String Makers pro printStringMaker as StringMaker """ Used by `print` statements, string substitutions and .toPrintString methods. """ get return CobraImp._printStringMaker set CobraImp._printStringMaker = value pro techStringMaker as StringMaker """ Used by `assert` failures, `trace` statements and .toTechString methods. """ get return CobraImp._techStringMaker set CobraImp._techStringMaker = value ## Program stuff get commandLineArgs as List return List(Environment.getCommandLineArgs) get exePath as String """ Returns the full path of the currently executing exe including directory, file name and extension. Use `Path.getDirectoryName()` on this to get the directory containing the current exe. """ test assert '.exe' in CobraCore.exePath body return Assembly.getEntryAssembly.location def exit(exitCode as int) """ Exits the process. """ Environment.exit(exitCode) get newLine as String """ Returns the newline for the current environment/platform. """ return Environment.newLine get printDestination as TextWriter """ Returns the TextWriter that print statements currently print to. This can change via the block version of the `print to` statement. """ return CobraImp.printDestination def printDebuggingTips print 'An unhandled exception has occurred.' print print 'Cobra debugging tips:' # Now the default: #print ' To get file name and line number information for the stack frames, use:' #print ' cobra -debug foo.cobra' if CobraCore.isRunningOnMono print ' If running the executable through "mono" then use --debug (double dash):' print ' mono --debug foo.exe ...' print ' To get a post-mortem, HTML-formatted report with more details about your objects:' print ' cobra -debug -exception-report foo.cobra' print ' For even more information, try:' print ' cobra -debug -exception-report -detailed-stack-trace foo.cobra' print ' Or use the abbreviations:' print ' cobra -d -er -dst foo.cobra' print ' See also: http://cobra-language.com/trac/cobra/wiki/DebuggingTopics' print ' You can turn off this message with -debugging-tips:no or -d' print ## Reset def reset(printDestination as TextWriter) """ Resets the Cobra run-time support using the argument as the initial print destination on the "print to" stack. This is occasionally needed in special circumstances such as running with Pex (http://research.microsoft.com/pex/). """ CobraImp.reset(printDestination) def reset """ Resets the Cobra run-time support using Console.out. """ .reset(Console.out) ## Tracer var _tracer as Tracer? pro tracer as Tracer """ The global Tracer object used by `trace` statements. Via this property, you can set this to your own instance, or access the tracer to read or write its properties. To turn off tracing, for example, you can write `CobraCore.tracer.isActive = false`. """ get if _tracer is nil _tracer = Tracer() return _tracer to ! set _tracer = Tracer() ## Run Tests def runAppTests _runAllTests(false) def runAllTests _runAllTests(true) def _runAllTests(deep as bool) """ Run Cobra `test` sections in all assemblies using reflection to locate them. Default is to just run tests in this assembly. If `deep` is true will also run tests in all referenced libraries as well """ if CobraImp.showTestProgress, listener = Cobra.Core.Test.TextWriterListener(Console.out) else, listener = Cobra.Core.Test.TextWriterOnlyOnFailureListener(Console.out) tr = Cobra.Core.Test.TestRunner(listener) if deep, tr.params.willTestLibraries = true tr.runAllTests if listener.testFailures, CobraCore.exit(1) ## Detailed stack trace pro maxStackFrames as int """ When detailed stack trace is on, this value limits the maximum stack depth before Cobra will exit with a stack overflow error including a listing of the most recent stack frames. The default value is 250. You can set to 0 to disable stack overflow detection. """ get return CobraImp._maxStackFrames set require value == 0 or value > 9 CobraImp._maxStackFrames = value pro numLastMaxStackFrames as int """ When stack overflow is detected, this value gives the number of most recent stack frames that will be printed. """ get return CobraImp._numLastMaxStackFrames set require value >= 2 CobraImp._numLastMaxStackFrames = value var _maxDumpObjectCount = 250 pro maxDumpObjectCount from var """ Controls the maximum number of objects dumped in the exception report. Defaults to 250 which can easily result in a 5MB exception report. """ get hasDetailedStackTrace return CobraImp.hasDetailedStackTrace def handleUnhandledException(ex as Exception) print try print 'Unhandled Exception: [ex]' catch exc as Exception print 'Unhandled Exception: CAUGHT EXCEPTION FOR [ex.getType.name].toString: [exc]' fileName = 'cobra-exception-report.html' print 'Writing exception report to [fileName]...' using tw = File.createText(fileName) HtmlExceptionReportWriter().writeReport(tw, ex) print 'Wrote [fileName]' didOpen = false for envVarName in ['COBRA_OPEN_HTML_ER_COMMAND', 'COBRA_OPEN_HTML_SST_COMMAND'] # SST is old. "super stack trace" cmd = Environment.getEnvironmentVariable(envVarName) if cmd and cmd.trim.length p = System.Diagnostics.Process() p.startInfo.fileName = cmd p.startInfo.arguments = fileName p.startInfo.useShellExecute = false p.start print '[cmd] [fileName]' didOpen = true continue if not didOpen print 'You can set the environment variable COBRA_OPEN_HTML_ER_COMMAND' print 'to automatically open the exception report.' ## Type names and tech strings def typeName(t as Type) as String return CobraImp.typeName(t) def toTechString(x as Object?) as String return CobraImp.toTechString(x) ## Will check control flags # CC: make a public section/block here var _willCheckInvariant = true is public var _willCheckRequire = true is public var _willCheckEnsure = true is public var _willCheckAssert = true is public var _willCheckNil = true is public pro willCheckInvariant from var pro willCheckRequire from var pro willCheckEnsure from var pro willCheckAssert from var pro willCheckNil from var set willCheckAll as bool .willCheckInvariant = value .willCheckRequire = value .willCheckEnsure = value .willCheckAssert = value .willCheckNil = value ## Finding cobra command line program # to-do: 2013-05-09 CE: Remove after next release. def runCobraExe(args as String, process as out System.Diagnostics.Process?) as String """ Deprecated. See CobraCommand.cobra. """ r = CobraCommand.find.run(args) process = r.process return r.output def runCobraExe(cobraPath as String, args as String, process as out System.Diagnostics.Process?) as String """ Deprecated. See CobraCommand.cobra. """ require cobraPath.length r = CobraCommand(cobraPath).run(args) process = r.process return r.output def findCobraExe as String? """ Deprecated. See CobraCommand.cobra. """ return CobraCommand.find.path # logically should be .findExe, but .find is for legacy def findCobraExe(extraPaths as IList?) as String? """ Deprecated. See CobraCommand.cobra. """ return CobraCommand.find(extraPaths).path # logically should be .findExe, but .find is for legacy def clearCobraExeCache """ Deprecated. See CobraCommand.cobra. """ CobraCommand.clearCache ## Other util def hasContracts as bool """ Returns true if the current process was compiled with -include-contracts:yes (the default). This enables you to determine at run-time if contracts are present. At least one use for this is: if CobraCore.hasContracts expect RequireException, .someMethod else expect SomeOtherException, .someMethod """ try _hasContracts catch RequireException return true return false def _hasContracts require false pass get runtimePlatform as String return 'clr' #return 'jvm' # return 'objc' var _isRunningOnMono as bool? def isRunningOnMono as bool """ Returns true if the current process is running on the Mono VM (as opposed to Microsoft .NET). """ if _isRunningOnMono is nil _isRunningOnMono = sharp'System.Type.GetType("Mono.Runtime")' is not nil return _isRunningOnMono to ! def isRunningOnMac as bool """ Returns true if the current process is running on Mac OS X. """ return .isRunningOnUnix and _ all for dir in '/System /Library /Applications'.split get Directory.exists(dir) def isRunningOnUnix as bool """ Returns true if the current process is running on Unix/Posix/Linux/BSD/etc. """ platform = Environment.osVersion.platform to int return platform in [4, 6, 128] # http://www.mono-project.com/FAQ:_Technical def isRunningOnWindows as bool """ Returns true if the current process is running on Microsoft Windows. """ return not .isRunningOnUnix var _hasMonoVersionString as bool var _monoVersionString as String? def monoVersionString as String? """ Returns a string such as "2.0" or "1.2.6" or nil if a version number cannot be determined (usually indicating that Mono is not present). """ if not _hasMonoVersionString _hasMonoVersionString = true mrt = sharp'System.Type.GetType("Mono.Runtime")' to Type? if mrt mi = mrt.getMethod('GetDisplayName', BindingFlags(Public, NonPublic, Static)) if mi ret = mi.invoke(nil, nil) if ret inherits String s = ret.trim if s.startsWith('Novell'), s = s.replace('Novell', '').trim if s.startsWith('Mono'), s = s.replace('Mono', '').trim _monoVersionString = s return _monoVersionString var _random as Random? get random as Random """ Returns a globally shared, random number generator (created on first request). """ if _random is nil, _random = Random() return _random to ! def noOp(args as vari dynamic?) as dynamic? """ No operation. Primarily used in Cobra's own test suite to consume a local variable to avoid undesired warnings. Takes any number of values and returns an undefined value of type `dynamic?` for maximum flexibility. """ return 0 var _htmlEncodes = @[['&', '&'], ['<', '<'], ['>', '>'], ['"', '"']] def htmlEncode(obj as Object?) as String """ Return the HTML encoded version of the given object. Returns the contents of the object if it is an instance of Html. This is useful to display a plain ASCII text string on a web page. """ if obj is nil, return '' if obj inherits Html, return obj.contents return .htmlEncode(obj.toString) def htmlEncode(s as String?) as String """ Return the HTML encoded version of the given string. This is useful to display a plain ASCII text string on a web page. """ test assert .htmlEncode('foo') == 'foo' assert .htmlEncode('3 < 5') == '3 < 5' body if s is nil, return '' for code in _htmlEncodes s = s.replace(code[0], code[1]) return s to ! def htmlDecode(s as String?) as String """ Return the HTML decoded version of the given string. """ test assert .htmlDecode('foo') == 'foo' assert .htmlDecode('3 < 5') == '3 < 5' body if s is nil, return '' for code in _htmlEncodes s = s.replace(code[1], code[0]) return s to ! def urlEncode(s as String?) as String """ Return a version of the string encoded for and safe to use in URLs. """ return UrlUtils.encode(s) def urlDecode(s as String?) as String """ Return the decoded version of a URL encoded string. """ return UrlUtils.decode(s) def singleCompare(left, op as String, right) as bool test cases = [[0, "GT", -0.1, true], [0, "GE", -0.1, true], [0, "LT", -0.1, false], [0, "LE", -0.1, false]] for left, op, right, answer in cases assert .singleCompare(left, op, right) == answer body branch op on 'EQ', return left == right on 'NE', return left <> right on 'GT', return left > right on 'LT', return left < right on 'GE', return left >= right on 'LE', return left <= right on 'IS', return left == right on 'ISNOT', return left <> right else, throw FallThroughException(op) def chainedComparison(stuff as vari dynamic) as bool things = List(stuff) for index in 0 : things.count - 1 : 2 if not .singleCompare(things[index], things[index + 1], things[index + 2]) return false return true def operatingSystemDescription as String """ Returns a human readable description of the operating system such as: Microsoft Windows NT 6.1.7601 Service Pack 1 Ubuntu 12.04 LTS Mac OS X 10.6.8 """ name = '' if File.exists('/System/Library/CoreServices/SystemVersion.plist') # Mac content = File.readAllText('/System/Library/CoreServices/SystemVersion.plist') match = Regex.match(content, r'(Mac[^<]+)') if match.success, name += match.groups[1].toString match = Regex.match(content, r'(\d+\.[\d\.]+)') if match.success, name += ' ' + match.groups[1].toString else if File.exists('/etc/lsb-release') # Ubuntu, ... content = File.readAllText('/etc/lsb-release') d = Dictionary() for line in content.splitLines line = line.trim if line == '' or line.startsWith('#') or '=' not in line, continue pair = line.split('=', 2) d[pair[0].trim] = pair[1].trim if d.containsKey('DISTRIB_DESCRIPTION'), name = d['DISTRIB_DESCRIPTION'].trim if name == '' try name = d['DISTRIB_ID'] + ' ' + d['DISTRIB_RELEASE'] catch pass if name.startsWith('"') and name.endsWith('"'), name = name[1:-1] else if File.exists('/etc/arch-release') # Arch Linux name = 'Arch Linux ' + _getCommandOutput('/bin/uname', '-r').trim pacman = _getCommandOutput('pacman', '--version') match = Regex.match(pacman, r'[Pp]acman v?(\d+\.[\d\.]+)') if match.success, name += ' (pacman ' + match.groups[1].toString.trim + ')' else if File.exists('/etc/system-release') # CentOS, Fedora, ... name = File.readAllText('/etc/system-release') else if File.exists('/etc/redhat-release') # RedHat, ... name = File.readAllText('/etc/redhat-release') if name == '' # everyone else name = Environment.osVersion.toString name = name.trim return name def _getCommandOutput(command as String, args as String) as String p = System.Diagnostics.Process() p.startInfo.fileName = command p.startInfo.arguments = args p.startInfo.useShellExecute = false try return p.runAndCaptureAllOutput.trim catch # specific to users of this method: return '' rather than error return ''