Doxygen lists within exception tags render incorrectly - documentation

A list in the main doc of a symbol...
/**
* - foo
* - bar
* - wah
*/
renders nicely in Doxygen as bullet points:
The Doxygen documentation for the exception tag includes:
The text of the paragraph [after #exception] has no special internal structure. All visual enhancement commands may be used inside the paragraph. Each exception description will start on a new line. The \exception description ends when a blank line or some other sectioning command is encountered.
Despite that "all visual enhancement commands may be used inside the paragraph", it seems that lists cannot render correctly inside exception tags, possibly due to the strict handling of line ends.
The same list, inside an exception tag...
/**
* #exception myError
* - foo
* - bar
* - wah
*/
renders as bullet points strangely spaced apart:
It is possible Doxygen interprets each element of the list as a separate "exception description", and as such, separates them by newlines.
How can I avoid this behaviour, such that lists render as bullet points in the same way they do in the main doc?
I'm using Doxygen 1.8.13 on Ubuntu 18.04. Here is my doxygen config file which renders the below MWE incorrectly:
/**
* - foo
* - bar
* - wah
* #exception myError
* - foo
* - bar
* - wah
*/
void myFunc();

Doxygen 1.8.13 is already a bit older (December 2016), I certainly advise to update to the current version 1.9.1 but this is not the cause of the problem/.
The provided Doxyfile is not really minimal and contains a lot of project specific stuff not relevant for the issue at hand. A doxyfile with
EXTRACT_ALL=YES
QUIET=YES
is sufficient.
When running the given input we get:
The question is where do we want to have the word Exceptions and the subsequent list items?
Currently the first set of list items is not terminated till after the second - wuh and the Exceptions is seen as part of the first wuh list item and the second foo is seen as a level 1 list item hence the above shown output.
A solution (not the extra space before the items after the #exception making it here a second level list):
/**
* - foo
* - bar
* - wah
* #exception myError
* - foo
* - bar
* - wah
*/
void myFunc();
result:
Probably the wanted solution (note the empty line before #exception which terminates the first list):
/**
* - foo
* - bar
* - wah
*
* #exception myError
* - foo
* - bar
* - wah
*/
void myFunc();
~
result:
(I ran everything with the 1.8.13 version)

Related

How to get variable from feature, which is using in karate.repeat?

I need to create 2 items, use get method to check if everything is ok and after that I should delete these items.
I have 1 tc - getItem, which uses 2 helpers (postItem and deleteItem).
For getItem I need to have itemId, which I get from postItem, where this variable is defined. After that I use the same itemId for deleteItem as afterhook. What I do:
Feature:get item
Background:Pre-conditions
* url apiUrl
* call read('classpath:/helpers/features/postItem.feature')
* configure afterScenario = function(){karate.call('classpath:/helpers/features/deleteItem.feature')}
Scenario: Get items
* path '/items/'
And param id = itemId
When method Get
Then status 200
It works but I create only 1 item and delete it correctly because itemId is predefined in postItem and I`m able to re-use it. I saw how to use karate.repeat from HERE but when I do the next
* def item = function(i){ return karate.call ('classpath:/helpers/features/postItem.feature')}
I`m not able to get itemId and as a result not able to delete it. Have tried to use
* print item.response
but it is "null"
So I have 2 questions:
How to get variable from postItem
How to delete each of these created items using afterHook?
May I offer some advice. I would NOT try to create helpers and re-use them like this. Please take some time to read this, and then you may understand: https://stackoverflow.com/a/54126724/143475
I would definitely not use a hook also. Please think of the people who need to maintain your test in the future, they will cry.
Here is how I would write your test. And let me repeat, it is OK to repeat some code when your are doing test automation. For a real, working example, see here.
Background:
* url apiUrl + '/items'
Scenario:
* request {}
* method post
* status 201
* path response.id
* method get
* status 200
* request {}
* method post
* status 201
* path response.id
* method delete
# and so on
Otherwise, the only thing I will say is please refer to the documents on how you can call features and get data back in a loop without using karate.repeat() which should be used only for creating JSON arrays. You can see this answer which has an example and links to the documentation: https://stackoverflow.com/a/75394445/143475
Have found solution how can I do this using DRY pattern + afterhooks.
Feature:get items
Background:Pre-conditions
* url apiUrl
* def item = function(i){ return karate.call ('classpath:/helpers/features/postItem.feature')}
* def createdItem = karate.repeat(2, item )
* table createdItems
|itemId |
|createdItem[0].response.data.id|
|createdItem[1].response.data.id|
* configure afterScenario = function(){karate.call('classpath:/helpers/features/deleteItem.feature', createdItems )}
Scenario: Get all items
* path '/items'
When method Get
Then status 200
It works, but maybe it also can be updated. Im new in this)
So, basically, what I do:
I create 2 items, for get method using karate.repeat with calling postItem feature
I create table with itemId references
Create afterHook with calling deleteItem.feature, which should have argument itemId and I provide created table for this.
And I have scenario, which checks created items
And after that these created items are deleted by afterhooks.
As a result, I have clear scenario, which contains
Pre-conditions --> creating items (preparing data)
Scenario body --> GET method
Post-conditions --> deleting created items and returning to default state.
All of this I do because dont have DB read permission) In an ideal world, preparing data should be done via SQL and deleted as well)
Hope this will help someone)) Also, if you find better solution, feel free to write this here) Tnx

How to properly create and use dynamic Xpath in JSON (Page Object Model) - Karate DSL

For example, I have this sample JSON object in pages folder which contains all the XPaths for specific page.
{
"pageTitle1": "//*[#class='page-title' and text()='text1']",
"pageTitle2": "//*[#class='page-title' and text()='text2']",
"pageTitle_x" : "//*[#class='page-title' and text()='%s']"
}
* def pageHome = read('classpath:/pages/pageHome.json')
* click(pageHome.pageTitle_x) <-- how to properly replace %s in the string?
Update: I tried the replace function, not sure if this is the proper way.
* click(pageHome.pageTitle_x.replace("%s","new value"))
First a bit of advice. Trying to be "too clever" like this causes maintainability problems in the long run. I have said a lot about this here, please read it: https://stackoverflow.com/a/54126724/143475
That said, you can write re-usable JS functions that will do all these things:
* def pageTitle = function(x){ return "//*[#class='page-title' and text()='" + x "']" }
Now using that you can do this:
* click(pageTitle('foo'))
If you redesign the function even this may be possible:
* click(pageTitle(pageHome.pageTitle_x, 'foo'))
But see how things become more complicated and less readable. The choice is yours. Note that anything you can do in JS (e.g. String.replace()) will be possible, it is up to you and your creativity.

karate xpath - Can we replace/delete a node

I'm looking to test error messages by modifying a valid xml message file.
I can easily add nodes like this in the scenario:
* def invalidDocumentId = read('Valid.xml')
* set invalidDocumentId /soapenv:Envelope/soapenv:Body = <tis:extraBonus>Extra</tis:extraBonus>
Given request invalidDocumentId
But I'd like to also remove nodes, update node names, change attribute names.
Is there a way to set that or do I need to call Java com.intuit.karate.XmlUtils.
First, removing and adding a node and even attributes should be easy, just use the remove and set keywords with XPath. They will over-write values if needed.
* def base = <query><name>foo</name></query>
* remove base /query/name
* match base == <query/>
* set base /query/foo = 'bar'
* set base /query/#baz = 'ban'
* match base == <query baz="ban"><foo>bar</foo></query>
And the good news is that if you have some really tricky XML manipulation requirements, the string replace syntax comes to the rescue. This is best explained in this other answer on Stack Overflow: https://stackoverflow.com/a/50367134/143475 | https://stackoverflow.com/a/53682733/143475

What is "0E-20"

Im using a Model Based Testing tool (Conformiq).
It generates test cases with value "0" but when i export those test cases in java, the value written there is "0E-20"
What does that mean? What is "0E-20" ?
the code is somwhat like this :
new CQRecordNumber(
/** value */
(float)0E-20));
As per this Wiki page, xEy means x * 10^y, which, in your case, is 0 * 10^(-20)

Concrete5 attribute counts

We built a site with Concrete5 that was originally developed in Joomla. Our job was to bring over everything and Concrete5-ize it. A major part of this site is about 1200 audio teachings, with each teaching having various attributes, such as topic, author, program, location, etc.
Some teachings might have more than one attribute assigned, say multiple keywords or topics.
I would like to give counts to all of the attributes so that the visitor can see how many teachings are by a certain author, or how many are on a particular topic at a glance, ie:
Ethics (20)
Fear (42)
Gratitude (55)
My original code turned out to have way too much overheard to be practical for so many teachings and so many attributes. Basically, I ran through and for each attribute, I did a lookup for the total count based on the PageList count. We're talking hundreds of lookups with each page load. Turning on cache didn't seem to help here.
Are there any other strategies that have proved successful for aggregating counts for attributes over a large-ish number of pages?
Here is the site for reference: http://everydayzen.org/teachings/
I typically say "don't access the database directly; use the API", but I think you should be using the DB here.
Check out the [Collection|File]SearchIndexAttributes table. (I'm not sure if teachings are files or pages. If pages, you'll need to reindex them regularly, via the job in the dashboard.) Looking at the index table will be a lot easier than joining in the most-recent version in the attribute value table. Once you see that table, you can do some simple GROUPing within SQL.
If you want to use the API, you could do it as you do today as a batch, do the appropriate calculations, and then cache it.
There's no reason caching shouldn't work but the first hit (when the cache is cold) will, of course, take the full amount of time. You should cache my IndexAttributes idea (a full table read and looping isn't trivial), but at least with a cold cache that should take a fraction of a second vs 10 or more seconds that hundreds of page list calls could take.
I've done something similar on a job site for Concrete5, by showing the counts of each Department that jobs fall in.
i.e. HR (32), Sales (12) and so on
This is the code taken from a Helper that acheives this (this is just the related functions included):
<?php
class JobHelper {
/**
* GetDepartmentJobsCount
* Returns array of Department names with job count based on input Pages
* #param Array(Pages) - Result of a PageList->getPages
* #return Array
*/
public function getDepartmentJobsCount($pages) {
$depts = $this->getDepartments();
$cj = $this->setCounts($depts);
$cj = $this->setAttributeCounts($cj, $pages,'job_department');
return $cj;
}
/**
* GetDepartments
* Return all available Departments
* #return Array(Page)
*/
public function getDepartmentPages(){
$pld = new PageList();
$pld->filterByPath('/working-lv'); //the path that your Teachings all sit under
$pld->setItemsPerPage(0);
$res = $this->getPage();
$depts = array();
foreach($res as $jp){
$depts[$jp->getCollectionName()] = $jp;
}
ksort($depts);
return $depts;
}
/**
* PopulateCounts
* Returns array of page names and counts
* #param Array - Array to feed from
* #return Array
*/
public function setCounts($v){
foreach($v as $w){
$a[$w]['count'] = 0;
}
return $a;
}
/**
* PopulateCounts
* Returns array of page names, with counts added from attribute, and paths
* #param Array - Array to add counts and paths in to
* #param Array(Pages) - Pages to run through
* #param String - Attribute to also add to counts
* #param String - Optional - Job Search parameter, leave blank to get Page URL
* #return Array
*/
public function setAttributeCounts($cj, $pages, $attr){
foreach($pages as $p) {
$pLoc = explode('|',$p->getAttribute($attr)); // Our pages could have multiple departments pipe separated
foreach($pLoc as $locName){
$cj[$locName]['count']++;
}
}
return $cj;
}
You can then do the following from a PageList template
$jh = Loader::helper('job');
$deptCounts = $jh->getDepartmentJobsCount($pages);
foreach($deptCounts as $dept => $data) {
echo $dept . '(' . $data['count] . ')';
}