I have a list of version numbers like,
Versions = [0.0.10, 0.0.11, 0.0.13, 0.0.14, 0.0.15, 0.0.16, 0.0.17, 0.0.18, 0.0.19, 0.0.20, 0.0.21, 0.0.22, 0.0.23, 0.0.24, 0.0.25, 0.0.26, 0.0.27, 0.0.28, 0.0.29, 0.0.3, 0.0.30, 0.0.33, 0.0.34, 0.0.35, 0.0.36, 0.0.37, 0.0.38, 0.0.39, 0.0.4, 0.0.41, 0.0.42, 0.0.43, 0.0.44, 0.0.45, 0.0.46, 0.0.47, 0.0.48, 0.0.49, 0.0.5, 0.0.5-delivery.5, 0.0.50, 0.0.51, 0.0.52, 0.0.53, 0.0.54, 0.0.55, 0.0.56, 0.0.57, 0.0.58, 0.0.59, 0.0.6, 0.0.60, 0.0.61, 0.0.62, 0.0.63, 0.0.64, 0.0.7, 0.0.8, 0.0.9]'
And i need to get the last version (0.0.64), Versions.sort() && Collections.max(Versions) doesn't work for me.
So I developed this function blow
def mostRecentVersion(def versions) {
def lastversion = "0.0.0"
for (def items : versions) {
def version = items.tokenize('-')[0]
def ver = version.tokenize('.')
def lastver = lastversion.tokenize('.')
if (lastver[0].toInteger() < ver[0].toInteger() ){
lastversion = version
}else if(lastver[0].toInteger() == ver[0].toInteger()) {
if (lastver[1].toInteger() < ver[1].toInteger() ){
lastversion = version
}else if(lastver[1].toInteger() == ver[1].toInteger()){
if (lastver[2].toInteger() < ver[2].toInteger() ){
lastversion = version
}
}
}
}
return lastversion }
i'm asking if there is something better,
Thank you for help :)
the idea:
build map with sortable key and original version value, then sort map by keys, then get only values
to create sortable key for each value
split version to digits & not-digit strings array
prepend to each part 0 to have minimum length 3 (assume each number not longer then 3 digits)
join array to string
so, for 0.11.222-dev ->
1. [ '0', '.', '11', '222', '-dev' ]
2. [ '000', '00.', '011', '222', '-dev' ]
3. '00000.011222-dev'
the code
def mostRecentVersion(versions){
return versions.collectEntries{
[(it=~/\d+|\D+/).findAll().collect{it.padLeft(3,'0')}.join(),it]
}.sort().values()[-1]
}
//test cases:
def fullVersions = ['0.0.10', '0.0.11', '0.0.13', '0.0.14', '0.0.15', '0.0.16',
'0.0.17', '0.0.18', '0.0.19', '0.0.20', '0.0.21', '0.0.22', '0.0.23', '0.0.24',
'0.0.25', '0.0.26', '0.0.27', '0.0.28', '0.0.29', '0.0.3', '0.0.30', '0.0.33',
'0.0.34', '0.0.35', '0.0.36', '0.0.37', '0.0.38', '0.0.39', '0.0.4', '0.0.41',
'0.0.42', '0.0.43', '0.0.44', '0.0.45', '0.0.46', '0.0.47', '0.0.48', '0.0.49',
'0.0.5', '0.0.5-delivery.5', '0.0.50', '0.0.51', '0.0.52', '0.0.53', '0.0.54',
'0.0.55', '0.0.56', '0.0.57', '0.0.58', '0.0.59', '0.0.6', '0.0.60', '0.0.61',
'0.0.62', '0.0.63', '0.0.64', '0.0.7', '0.0.8', '0.0.9']
assert mostRecentVersion(fullVersions) == '0.0.64'
assert mostRecentVersion(['0.0.5-delivery.5', '0.0.3', '0.0.5']) == '0.0.5-delivery.5'
assert mostRecentVersion(['0.0.5.5', '0.0.5-delivery.5', '0.0.5']) == '0.0.5.5'
I believe this will work... it also keeps the original version strings around, incase 0.5.5-devel.5 is the latest... It relies on the fact that Groovy will use a LinkedHashMap for the sorted map, so the order will be preserved :-)
def mostRecentVersion(def versions) {
versions.collectEntries {
[it, it.split(/\./).collect { (it =~ /([0-9]+).*/)[0][1] }*.toInteger()]
}.sort { a, b ->
[a.value, b.value].transpose().findResult { x, y -> x <=> y ?: null } ?:
a.value.size() <=> b.value.size() ?:
a.key <=> b.key
}.keySet()[-1]
}
def fullVersions = ['0.0.10', '0.0.11', '0.0.13', '0.0.14', '0.0.15', '0.0.16', '0.0.17', '0.0.18', '0.0.19', '0.0.20', '0.0.21', '0.0.22', '0.0.23', '0.0.24', '0.0.25', '0.0.26', '0.0.27', '0.0.28', '0.0.29', '0.0.3', '0.0.30', '0.0.33', '0.0.34', '0.0.35', '0.0.36', '0.0.37', '0.0.38', '0.0.39', '0.0.4', '0.0.41', '0.0.42', '0.0.43', '0.0.44', '0.0.45', '0.0.46', '0.0.47', '0.0.48', '0.0.49', '0.0.5', '0.0.5-delivery.5', '0.0.50', '0.0.51', '0.0.52', '0.0.53', '0.0.54', '0.0.55', '0.0.56', '0.0.57', '0.0.58', '0.0.59', '0.0.6', '0.0.60', '0.0.61', '0.0.62', '0.0.63', '0.0.64', '0.0.7', '0.0.8', '0.0.9']
assert mostRecentVersion(fullVersions) == '0.0.64'
assert mostRecentVersion(['0.0.5-delivery.5', '0.0.3', '0.0.5']) == '0.0.5-delivery.5'
assert mostRecentVersion(['0.0.5.5', '0.0.5-delivery.5', '0.0.5']) == '0.0.5.5'
Edit:
Made a change so that 0.5.5.5 > 0.5.5-devel.5
I need help in katalon studio groovy script for if else statement. If the element 'Page_Quick Inbound/input_Bad_quantity' is not found then it should skip the current iteration and continue with the next iteration. 12th line in the code I have tried the if statement but it is not working.
for (def row = 1; row <= findTestData('Ship Plan Data').getRowNumbers(); row++)
{
WebUI.delay(2)
WebUI.setText(findTestObject('Page_Quick Inbound/input_Scan or type SKU_itemId'),
findTestData('Ship Plan Data').getValue('fnsku', row))
rb.keyPress(KeyEvent.VK_ENTER)
WebUI.delay(1)
rb.keyRelease(KeyEvent.VK_ENTER)
WebUI.delay(2)
if (WebUI.verifyElementNotPresent(findTestObject('Page_Quick Inbound/input_Bad_quantity',10,FailureHandling.OPTIONAL) )==true)
{continue}
else{
WebUI.setText(findTestObject('Page_Quick Inbound/input_Bad_quantity'), findTestData('Ship Plan Data').getValue('Quantity',
row))
rb.keyPress(KeyEvent.VK_ENTER)
WebUI.delay(2)
rb.keyRelease(KeyEvent.VK_ENTER)
WebUI.delay(3)
WebUI.setText(findTestObject('Page_Quick Inbound/input_(You can select bin from'), findTestData('Ship Plan Data').getValue(
'bin', row))
rb.keyPress(KeyEvent.VK_ENTER)
WebUI.delay(2)
rb.keyRelease(KeyEvent.VK_ENTER)
WebUI.delay(2)
WebUI.click(findTestObject('Page_Quick Inbound/button_RECEIVE STORE'))
}
}
findTestObject() accepts strings as argument, so the integer and the failure handling need to go.
you have typo in if command:
if (WebUI.verifyElementNotPresent(findTestObject('Page_Quick Inbound/input_Bad_quantity'),10,FailureHandling.OPTIONAL) == true)
finTestObject(),10,FailureHandling
I'm rewriting some JUnit test into Spock to take advantage of the data driven test style.
I'm struggling a bit with how to provide the verification with something dynamic.
Here's what I have so far:
def "domestic rules"(from, to, oneWay, check) {
expect:
String mealResponse = getMealResponse(new BookingOptions.BookingOptionsBuilder().setFrom(from).setTo(to).setOneWay(oneWay).build());
check(mealResponse)
where:
from | to | oneWay || check
'MNL' | 'PEK' | true || assertNoMeals()
}
def assertNoMeals = {
assert JsonAssert.with(it)
.assertThat('$.links', hasSize(1))
.assertThat('$.links[0].rel', is("http://localhost:9001/api/docs/rels/ink/meal-allocations"))
.assertThat('$.links[0].uri', startsWith("http://localhost:9001/api/tenants/acme/meals/allocations/"));
}
Unfortunately, I get a NullPointerException at the line with the first row of data.
I guess thats because the closure is being run at that point, rather than just declared.
Is there a way to do this better?
Change
def "domestic rules"(from, to, oneWay, check) {
To
#Unroll
def "domestic rules from #from to #to one way #oneWay"() {
def "domestic rules"() {
when: 'get meals using certain parameters'
String mealResponse = getMealResponse(new BookingOptions.BookingOptionsBuilder().setFrom(from).setTo(to).setOneWay(oneWay).build())
then: 'the json response should contain some contents (improve the message here!)'
JsonAssert.with(mealResponse)
.assertThat('$.links', hasSize(1))
.assertThat('$.links[0].rel', is(somethingToUseInAssertions))
where:
from | to | oneWay || somethingToUseInAssertions
'MNL' | 'PEK' | true || 'just some example'
}
The above should help you get in the right track. Notice that you should have some values only in the examples. If you need some logic in the assertions, use a value which indicates what kind of assertion needs to be made... but it's a very bad idea to use a closure as an example.
If you really want to make your test hard to maintain and go ahead and use closures as "values" in your examples, then do something like this:
def "domestic rules"() {
when:
String mealResponse = getMealResponse(new BookingOptions.BookingOptionsBuilder().setFrom(from).setTo(to).setOneWay(oneWay).build())
then:
check(mealResponse)
where:
from | to | oneWay || check
'MNL' | 'PEK' | true || this.&assertNoMeals
}
boolean assertNoMeals(mealResponse) {
assert JsonAssert.with(mealResponse)
.assertThat('$.links', hasSize(1))
.assertThat('$.links[0].rel', is("http://localhost:9001/api/docs/rels/ink/meal-allocations"))
.assertThat('$.links[0].uri', startsWith("http://localhost:9001/api/tenants/acme/meals/allocations/"))
return true // pass!
}
I advise you to learn both Groovy and Spock before writing something that is more reasonable. It's not hard, but it does take at least a few hours!
When try this sample code:
use(groovy.time.TimeCategory) {
800.millisecond + 300.millisecond
}
in groovy web console, I get a funny result:
0.1100 seconds
Does any one know why this happens or how to fix it?
That looks like a bug, the TimeDuration contains 1100 milliseconds, but when it prints it out, it converts it wrongly to seconds.
I've added it to the Groovy JIRA as a bug EDIT It's now marked as FIXED for versions 2.0.6, 1.8.9 and 2.1.0
In the mean time, I guess you'll need to do your own converter from TimeDuration to String :-/
Edit
You could do something like this (and there is probably a neater way of doing it)
groovy.time.TimeDuration.metaClass.normalize = { ->
def newdmap = ['days','hours','minutes','seconds','millis'].collectEntries {
[ (it):delegate."$it" ]
}.with { dmap ->
[millis:1000,seconds:60,minutes:60,hours:24,days:-1].inject( [ dur:[ days:0, hours:0, minutes:0, seconds:0, millis:0 ], roll:0 ] ) { val, field ->
val.dur."$field.key" = dmap."$field.key" + val.roll
val.roll = val.dur."$field.key".intdiv( field.value )
val.dur."$field.key" = field.value < 0 ?
val.dur."$field.key" :
val.dur."$field.key" % field.value
val
}.dur
}
new TimeDuration( newdmap.days, newdmap.hours, newdmap.minutes, newdmap.seconds, newdmap.millis )
}
That adds a normalize method to TimeDuration, so then doing:
use(groovy.time.TimeCategory) {
800.millisecond + 300.millisecond
}.normalize()
Shows 1.100 seconds
I haven't done a huge amount of testing on that method, so be warned it could do with some unit tests to make sure it doesn't fall over with other situations.
I'm in the process of switching my Watir / FireWatir scripts over to use watir-webdriver and need a means in watir-webdriver to determine which type of browser the test is currently being executed against, (IE, FF, Chrome).
With Watir / FireWatir looking at the class of the browser would return either "Watir::IE" or "FireWatir:Firefox". Using that the code could be branched to execute browser specific code.
In watir-webdriver, the class of the browser is always "Watir::Browser", it doesn't vary when running IE, Firefox, or Chrome.
Does anyone know of a way in Ruby with watir-web-driver to identify the browser's type (i.e. IE, Firefox, Chrome)?
For example: With Watir / Firewatir define methods:
def is_ie?()
return self.class.to_s == "Watir::IE"
end
def is_firefox?()
return self.class.to_s == "FireWatir::Firefox"
end
Then invoke them like this...
if(browser.is_ie?)
# run the IE specific code
end
if(browser.is_firefox?)
# run the firefox specific code
end
Thanks in advance,
Joe
Try
browser.driver.browser #=> :firefox
Thanks that is just what I needed!
As I'm in a transition with some scripts ported over to Watir-WebDriver and some still needing to run under Watir / Firewatir I've updated mt method as follows, posting them in case someone else is in the same situation.
def is_chrome?()
if(is_webdriver? == true)
return (self.driver.browser.to_s.downcase == "chrome")
else
return (self.class.to_s == "ChromeWatir::Browser")
end
end
def is_firefox?()
if(is_webdriver? == true)
return (self.driver.browser.to_s.downcase == "firefox")
else
return (self.class.to_s == "FireWatir::Firefox")
end
end
def is_ie?()
if(is_webdriver? == true)
return (self.driver.browser.to_s.downcase == "internet_explorer")
else
return (self.class.to_s == "Watir::IE")
end
end
def is_webdriver?()
if($LOADED_FEATURES.to_s =~/watir-webdriver/)
return true
else
return false
end
end