I think these error codes correspond to Windows system error codes - see this page.

So -2 corresponds to "ERROR_FILE_NOT_FOUND" and -3 to "ERROR_PATH_NOT_FOUND"

It seems more likely that you would get -2 from ##class(%File).Delete(file,.return). passing a directory that simply doesn't exist to RemoveDirectory results in -3. Is RemoveDirectory actually returning that error code, or perhaps a different one?

Certain configuration steps must be taken to enable access to % classes in non-/csp/sys/... web applications. Here's a link to the documentation about that.

Also, rather than creating your own % classes, you might consider either using the %All namespace (see documentation) or starting the package name with %Z. Starting the class's package name with %Z will prevent the class from being overwritten upon upgrade (which is important!) and, as a bonus, would also allow access from non-/csp/sys/ web applications automatically (according to the documentation at the first link).

Here's one way, using some macros from %occKeyword.inc/%occReference.inc (for tClass/tMethod/tLine in the above example):

Set tClsCode = $$$comMemberArrayGet(tClass,$$$cCLASSmethod,tMethod,$$$cMETHimplementation,tLine)

Note that this ends up looking at the class definition, which may not actually be the same as what's compiled. (However, used in this context, there are bigger problems in that case; it seems that the class->routine code mapping from %Studio.Debugger:SourceLine is invalidated if the class is changed but not compiled. This makes sense, but is definitely something to keep in mind if you're using it.)

I'm curious - what are you trying to do with this? smiley

There actually is a way to get this information that should work in many cases, using %Studio.Debugger:SourceLine, but it's not really easy. Note that %Studio.Debugger comes with the warning:

This class is used internally by Caché. You should not make direct use of it within your applications. There is no guarantee made about either the behavior or future operation of this class.

That said, here's a quick sample:

Class DC.Demo.SourceLine
{

ClassMethod Run()
{
    #; Here are a few comments to screw things up.
    Try {
        #; More comments!
        Write "Hello world",!
        Write 1/0
    } Catch e {
        Do ..HandleException(e)
    }
}

ClassMethod HandleException(pException As %Exception.AbstractException)
{
    Write "Exception occurred: ",pException.DisplayString(),!
    
    //Example value if e.Location (from above error): zRun+3^DC.Demo.SourceLine.1
    Set tSC = ..GetClassSourceLine(pException.Location,.tClsLocation)
    If $$$ISERR(tSC) {
        Write $System.Status.GetErrorText(tSC),!
    } else {
        Write ".INT error location: "_pException.Location,!
        Write ".CLS error location: "_tClsLocation,!
    }
}

ClassMethod GetClassSourceLine(pIntLocation As %String, Output pClsLocation As %String) As %Status
{
    Set tStatus = $$$OK
    Set pClsLocation = ""
    Try {
        Set tMethodAndLine = $Piece(pIntLocation,"^",1)
        Set tIntName = $Piece(pIntLocation,"^",2)
        Set tTag = $Piece(tMethodAndLine,"+")
        Set tRelativeOffset = $Piece(tMethodAndLine,"+",2)
        
        // Get routine text to find the absolute offset of tTag
        Set tTagOffset = 0
        Set tEndPos = 0
        Set tTextLines = 0
        For {
            Set tLine = $Text(@("+"_$Increment(tTextLines)_"^"_tIntName))
            Quit:tLine=""
            
            // Example:
            // zRun() public {
            // This relies on an assumption that methods will be sorted alphabetically and won't contain labels.
            If $Extract(tLine,1,$Length(tTag)) = tTag {
                Set tTagOffset = tTextLines //tTextLines is the counter.
                Set tEndPos = $Length(tLine)
                Quit
            }
        }
        
        // The absolute offset of the line in the .int file is the tag's offset plus the offset within it.
        Set tOffset = tTagOffset + tRelativeOffset
        Set tStatus = ##class(%Studio.Debugger).SourceLine(tIntName,tOffset,0,tOffset,tEndPos,,.tMap)
        If $$$ISERR(tStatus) {
            Quit
        }
        If $Data(tMap("CLS",1)) {
            Set $ListBuild(tClass,tMethod,tLine,tEndPos,tNamespace) = tMap("CLS",1)
            Set pClsLocation = tClass_":"_tMethod_"+"_tLine
        }
    } Catch e {
        Set tStatus = e.AsStatus()
    }
    Quit tStatus
}

}

And sample output:

USER>d ##class(DC.Demo.SourceLine).Run()
Hello world
Exception occurred: <DIVIDE> 18 zRun+3^DC.Demo.SourceLine.1
.INT error location: zRun+3^DC.Demo.SourceLine.1
.CLS error location: DC.Demo.SourceLine:Run+5

If an exception occurs in generated code, I'd expect this to be useless.

There isn't a built-in method that does exactly what you're looking for, that I know of. Here's a simple example of how to do it, though:

Class DC.Demo.ArrayUtils
{

ClassMethod ArrayObjectToArray(pSource As %Collection.AbstractArray, Output pTarget)
{
    Kill pTarget
    
    Set tKey = ""
    For {
        Set tItem = pSource.GetNext(.tKey)
        Quit:tKey=""
        Set pTarget(tKey) = tItem
    }
}

ClassMethod ArrayToArrayObject(ByRef pSource, pTarget As %Collection.AbstractArray)
{
    // Could initialize pTarget here and return it Output, or return it normally.
    // This is just a bit more general because it'll work with any array collection type.
    Do pTarget.Clear()
    
    Set tKey = ""
    For {
        Set tKey = $Order(pSource(tKey),1,tItem)
        Quit:tKey=""
        Do pTarget.SetAt(tItem,tKey)
    }
}

}

Usage:

USER>s aodt=##class(%ArrayOfDataTypes).%New()
 
USER>w aodt.SetAt("lcavanaugh","username")
1
USER>w aodt.SetAt("organization","coolcompany")
1
USER>zw aodt
aodt=<OBJECT REFERENCE>[1@%Library.ArrayOfDataTypes]
+----------------- general information ---------------
|      oref value: 1
|      class name: %Library.ArrayOfDataTypes
| reference count: 2
+----------------- attribute values ------------------
|Data("coolcompany") = "organization"
|   Data("username") = "lcavanaugh"
|        ElementType = "%String"
+-----------------------------------------------------
 
USER>do ##class(DC.Demo.ArrayUtils).ArrayObjectToArray(aodt,.array)
 
USER>zw array
array("coolcompany")="organization"
array("username")="lcavanaugh"
 
USER>s newaodt = ##class(%Library.ArrayOfDataTypes).%New()
 
USER>do ##class(DC.Demo.ArrayUtils).ArrayToArrayObject(.array,newaodt)
 
USER>zw newaodt
newaodt=<OBJECT REFERENCE>[2@%Library.ArrayOfDataTypes]
+----------------- general information ---------------
|      oref value: 2
|      class name: %Library.ArrayOfDataTypes
| reference count: 2
+----------------- attribute values ------------------
|Data("coolcompany") = "organization"
|   Data("username") = "lcavanaugh"
|        ElementType = "%String"
+-----------------------------------------------------

If you really wanted to make BuildValueArray work:

USER>d aodt.%SerializeObject(.serial)
 
USER>d aodt.BuildValueArray($lg(serial),.anotherarray)
 
USER>zw anotherarray
anotherarray("coolcompany")="organization"
anotherarray("username")="lcavanaugh"

The utility method approach would probably at least be clearer. smiley

Stepping back a bit:

What endpoint are you using? From Terminal, I see different certificates for googleapis.com and www.googleapis.com:

USER>set old = $io set dev = "|TCP|443" open dev:("googleapis.com":443:/TLS="Demo") use dev w 123,! use dev s cer = $System.Security.Users.SSLGetPeerCertificate() use old w $System.Encryption.X509GetField(cer,"Subject"),!,$System.Encryption.X509GetField(cer,"Extension:subjectAltName")
CN=www.google.com,O=Google Inc,L=Mountain View,ST=California,C=US
DNS:www.google.com

USER>close dev set old = $io set dev = "|TCP|443" open dev:("www.googleapis.com":443:/TLS="Demo") use dev w 123,! use dev s cer = $System.Security.Users.SSLGetPeerCertificate() use old w $System.Encryption.X509GetField(cer,"Subject"),!,$System.Encryption.X509GetField(cer,"Extension:subjectAltName")
CN=*.googleapis.com,O=Google Inc,L=Mountain View,ST=California,C=US
DNS:*.googleapis.com, DNS:*.clients6.google.com, DNS:*.cloudendpointsapis.com, DNS:cloudendpointsapis.com, DNS:googleapis.com

However, in my browser, if I navigate to https://googleapis.com, I see the googleapis.com certificate (and a 404 error). This difference in behavior might have something to do with Caché's lack of support for Server Name Indication (SNI).

Regardless, what happens if you change the endpoint to www.googleapis.com rather than googleapis.com?

LOGIN^%ZSTART could do the trick. See the documentation.

For example, put this in %ZSTART.mac:

    Quit

LOGIN
    Do ^%CD
    Quit

Then, when you log in to terminal, you'll get:

Username: tleavitt
Password: ***
Namespace: ?
 
    '?' for help.
    '@' (at-sign) to edit the default, the last namespace
        name attempted.  Edit the line just as if it were
        a line of code.
    <RETURN> will leave you in the current namespace.
Here are the defined namespaces:
     %SYS

     ...
Namespace: USER
You're in namespace USER
Default directory is c:\intersystems\ensemble2\mgr\user\
USER>

If you wanted to make this a per-user setting, it'd take a bit more work, but would certainly be possible.

Assuming you're doing this using the Studio extension framework, the class reference for %Studio.Extension.Base has really helpful documentation.

I think the pattern you want is:

In UserAction, return Action = 7 for your menu item(s):

7 - Display a dialog with a textbox and Yes/No/Cancel buttons. The text for this dialog is provided by the 'Target' return argument. The initial text for the textbox is provided by the 'Msg' return argument

The user can enter a password in this dialog. Then, in AfterUserAction, you can handle the user's response.

The best tool I've seen for tracking unit test coverage in Caché ObjectScript is https://github.com/litesolutions/cache-utcov - maybe you'd already found that from some old Developer Community posts. However, it's gone stale, it's not really mature/complete, and it doesn't have a solution for the problem you've described. There are further complications because %Monitor.System.LineByLine looks at the generated (.int) code, which contains code that isn't in the class definition (because it's generated) and may not contain code that is in the class (for example, a classmethod that returns a constant). It also looks at code line-by-line, and there may be multiple statements on a line; tracing with ZBREAK instead could be a solution for this.

It's worth noting that #; comments don't appear in .int code - so, if only this type of comment is used, you could accurately measure the percentage of code coverage for a method/classmethod as the percentage of code coverage of the generated .int code corresponding to the method/classmethod. Otherwise, you're stuck parsing the code (which, if you're just trying to detect comments, wouldn't be too bad) to detect lines that contain comments and omit them from consideration when determining code coverage percentage.

I've observed the same issue (garbage output) on a few occasions when there is output (i.e., write statements) before HTTP headers are written. The garbage output might be a CSP Gateway issue, but it is wrong to write prior to headers anyway.

Other than redesigning the class entirely, one thing to try might be outputting headers at the beginning of OnHTTPHeader: 

Set tStatus = %response.WriteHTTPHeader(.OutputBody)

It looks like this doesn't happen automatically if OnHTTPHeader is overridden. Note that %response.WriteHTTPHeader(.OutputBody) will indicate "don't call OnPage" (OutputBody = 0) if there's a redirect or server-side redirect. It's worth considering how your custom OnHTTPHeader behavior should interact with redirects.