Index: openacs-4/packages/acs-api-browser/tcl/test/acs-api-browser-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-api-browser/tcl/test/acs-api-browser-procs.tcl,v diff -u -r1.4 -r1.5 --- openacs-4/packages/acs-api-browser/tcl/test/acs-api-browser-procs.tcl 19 Jul 2018 11:46:57 -0000 1.4 +++ openacs-4/packages/acs-api-browser/tcl/test/acs-api-browser-procs.tcl 3 Sep 2024 15:37:30 -0000 1.5 @@ -22,7 +22,705 @@ aa_true "api documentation proc can document itself" \ [string match "*packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl*" $result] } + } + +aa_register_case \ + -cats { api smoke } \ + -procs { + api_add_to_proc_doc + } \ + acs_api_browser_api_add_to_proc_doc { + Check api_add_to_proc_doc + } { + set proc_name [ad_generate_random_string] + set property [ad_generate_random_string] + set value [ad_generate_random_string] + set value2 ${value}2 + + # + # Silence Warning: api_add_to_proc_doc: no proc_doc available for + # + aa_silence_log_entries -severities {warning} { + api_add_to_proc_doc \ + -proc_name $proc_name \ + -property $property \ + -value $value + } + + aa_true "nsv was created" [nsv_exists api_proc_doc $proc_name] + + aa_true "nsv contains the property" [dict exists [nsv_get api_proc_doc $proc_name] $property] + + aa_true "Property has 1 value" \ + {[llength [dict get [nsv_get api_proc_doc $proc_name] $property]] == 1} + aa_log "Adding the same value again" + api_add_to_proc_doc \ + -proc_name $proc_name \ + -property $property \ + -value $value + aa_true "Property still has 1 value" \ + {[llength [dict get [nsv_get api_proc_doc $proc_name] $property]] == 1} + + aa_log "Adding a different value" + api_add_to_proc_doc \ + -proc_name $proc_name \ + -property $property \ + -value $value2 + aa_true "Property now has 2 values" \ + {[llength [dict get [nsv_get api_proc_doc $proc_name] $property]] == 2} + + nsv_unset -nocomplain -- api_proc_doc $proc_name + } + +aa_register_case \ + -cats { api smoke } \ + -procs { + api_apropos_functions + } \ + acs_api_browser_api_apropos_functions { + Check api_apropos_functions + } { + set all_ad_procs [nsv_array names api_proc_doc] + + aa_true "Searching for the empty string returns every ad_proc" \ + {[llength [api_apropos_functions ""]] == [llength $all_ad_procs]} + + while {[set bogus_proc [ad_generate_random_string]] in $all_ad_procs} {} + aa_true "A bogus proc returns no result" \ + {[llength [api_apropos_functions $bogus_proc]] == 0} + + set proc ns_write + set found_p false + foreach r [api_apropos_functions $proc] { + lassign $r name etc + if {$name eq $proc} { + set found_p true + break + } + } + aa_false "Builtin '$proc' is not returned" $found_p + + set proc api_apropos_functions + set found_p false + foreach r [api_apropos_functions $proc] { + lassign $r name etc + if {$name eq $proc} { + set found_p true + break + } + } + aa_true "ad_proc '$proc' is retrieved correctly" $found_p + } + +aa_register_case \ + -cats { api smoke production_safe } \ + -procs { + api_describe_function + ad_looks_like_html_p + + util_wrap_list + } \ + acs_api_browser_api_describe_function { + Check api_describe_function + } { + aa_true "Searching for the empty string returns nothing" \ + {[string length [api_describe_function ""]] == 0} + + aa_true "A 'proper' search by an existing proc name returns some results" \ + {[string length [api_describe_function api_describe_function]] > 0} + + set default_results [api_describe_function api_describe_function] + set text_results [api_describe_function -format text/plain api_describe_function] + set html_results [api_describe_function -format text/html api_describe_function] + set anything_else_results [api_describe_function -format [ad_generate_random_string] api_describe_function] + + aa_true "Default format is text/plain" \ + {$default_results eq $text_results} + + aa_false "Text format looks like text" \ + [ad_looks_like_html_p $text_results] + + aa_true "HTML format looks like HTML" \ + [ad_looks_like_html_p $html_results] + + aa_true "Specifying a bogus format also returns HTML" \ + [ad_looks_like_html_p $anything_else_results] + } + +aa_register_case \ + -cats { api smoke } \ + -procs { + api_get_body + } \ + acs_api_browser_api_get_body { + Check api_get_body + } { + foreach proc_name [nsv_array names api_proc_doc] { + aa_true "Something similar to a tcl body is returned for '$proc_name'" \ + [info complete [api_get_body $proc_name]] + } + } + +aa_register_case \ + -cats { api smoke production_safe } \ + -procs { + api_proc_documentation + ad_looks_like_html_p + + util_wrap_list + } \ + acs_api_browser_api_proc_documentation { + Check api_proc_documentation + } { + set proc api_proc_documentation + + aa_true "Specifying an invalid proc throws an error" [catch { + api_proc_documentation [ad_generate_random_string] + }] + + set doc [api_proc_documentation $proc] + aa_true "Format is HTML" [ad_looks_like_html_p $doc] + + set doc [api_proc_documentation -format text/plain $proc] + aa_true "Format is HTML also when specifying deprecated -format flag" [ad_looks_like_html_p $doc] + + set proc_url [dict get [nsv_get api_proc_doc $proc] script] + set doc [api_proc_documentation -script $proc] + aa_true "Specifying the script flag returns the proc file" [string match *$proc_url* $doc] + + set doc [api_proc_documentation -xql $proc] + aa_true "Specifying the xql flag returns the something about xql" [string match -nocase *xql* $doc] + + set doc [api_proc_documentation -first_line_tag
[apidoc::get_doc_property $caller script]
[apidoc::get_doc_property $called script]
"
+ }
+ }
+ set package_key [apidoc::get_doc_property $called package_key ""]
+ if {$caller_package_key ne ""
+ && $package_key ne ""
+ && $caller_package_key ne $package_key
+ } {
+ # It is fine for acs-service-contract to invoke
+ # contract implementations.
+ if {$caller_package_key eq "acs-service-contract" &&
+ [info exists sc_aliases($called)]} {
+ continue
+ }
+ if {[apidoc::get_doc_property $called protection public] eq "private"
+ && ![string match AcsSc.* $caller]
+ } {
+ set msg "proc $caller_package_key.$caller calls private $package_key.$called"
+ if {$caller_deprecated_p} {
+ aa_log_result warning "deprecated $msg"
+ } else {
+ aa_error "$msg[apidoc::get_doc_property $caller script]
[apidoc::get_doc_property $called script]
"
+ }
+ }
+ }
+ }
+ }
+ }
+
+aa_register_case \
+ -cats {smoke production_safe} \
+ -procs {
+ aa_error
+ api_called_proc_names
+ apidoc::get_doc_property
+ template::adp_init
+
+ ds_adp_start_box
+ ds_adp_end_box
+ } \
+ callgraph__bad_page_calls {
+
+ Checks for calls of deprecated procs and for private calls in
+ other packages. Remember: "private" means "package private", a
+ "private" proc must be only directly called by a proc of the
+ same package
+
+ This test covers only calls from adp pages.
+
+ @author Gustaf Neumann
+
+ @creation-date 2020-03-12
+ } {
+
+ #
+ # Iterate over all package_keys
+ #
+ set count 0
+ foreach package_key [db_list _ {select package_key from apm_package_types order by 1}] {
+ #
+ # Process the content pages of the package.
+ #
+ set processed 0
+ foreach path [apm_get_package_files -package_key $package_key -file_types content_page] {
+ set type [string range [file extension $path] 1 end]
+ if {$type in {tcl adp}} {
+ #
+ # Just call the template compiler for every
+ # template to populate the cache for all
+ # templates. These entries are needed below to
+ # apply the usual code-analysis on it. The "call"
+ # is never executed.
+ #
+ set stub $::acs::rootdir/packages/$package_key/[file rootname $path]
+ append _ $package_key/$path \n
+ set call [template::adp_init $type $stub]
+ incr processed
+ } else {
+ append _ "ignore $package_key/$path (type $type)\n"
+ }
+ }
+ append _ "$package_key ($processed files)\n"
+ aa_log "$package_key ($processed files)"
+ #if {$count > 2} break
+ }
+
+ #aa_log "[ns_quotehtml $_]" + # + # Collect the compiled artefacts + # + set procs {} + foreach ns [lmap ns [namespace children ::template::code] {set ns}] { + lappend procs {*}[info commands ${ns}::*] + } + + foreach caller [lsort -dictionary $procs] { + #set caller db_transaction + set called_procs [api_called_proc_names -proc_name $caller] + set caller_deprecated_p [apidoc::get_doc_property $caller deprecated_p 0] + set caller_package_key [apidoc::get_doc_property $caller package_key ""] + set caller_name $caller + if {[regexp {template::code::tcl::(.*)$} $caller _ path]} { + set caller_name $path.tcl + regexp {/packages/([^/]+)/} $path _ caller_package_key + } + if {[regexp {template::code::adp::(.*)$} $caller _ path]} { + set caller_name $path.adp + regexp {/packages/([^/]+)/} $path _ caller_package_key + } + foreach called $called_procs { + #ns_log notice "$caller calls $called" + set msg "page $caller_name calls deprecated proc: $called" + if {[apidoc::get_doc_property $called deprecated_p 0]} { + if {$caller_deprecated_p} { + aa_log_result warning "deprecated $msg" + } else { + aa_error "$msg
$caller_name
[apidoc::get_doc_property $called script]
"
+ }
+ }
+ set package_key [apidoc::get_doc_property $called package_key ""]
+ if {$caller_package_key eq ""} {
+ aa_log "caller package key '$caller_package_key' $caller_name"
+ }
+ if {$caller_package_key ne ""
+ && $package_key ne ""
+ && $caller_package_key ne $package_key
+ } {
+ #aa_log "$caller from $caller_package_key calls $package_key.$called [apidoc::get_doc_property $called protection public]"
+ if {[apidoc::get_doc_property $called protection public] eq "private"
+ && ![string match AcsSc.* $caller]
+ } {
+ set msg "page $caller_name calls private $package_key.$called"
+ if {$caller_deprecated_p} {
+ aa_log_result warning "deprecated $msg"
+ } else {
+ aa_error "$msg$caller_name
[apidoc::get_doc_property $called script]
"
+ }
+ }
+ }
+ }
+ }
+ }
+
+aa_register_case -cats {
+ web
+ smoke
+} -urls {
+ /api-doc/
+ /api-doc/proc-search
+} acs_api_browser_search {
+ Simple test to search for a proc in the API-browser
+
+ @author Héctor Romojaro