Groovy for testers

Groovy for testers

Kick-off

println "os.arch: " + System.getProperty("os.arch") println "java -version".execute().err.text println "GroovySystem.version: " + GroovySystem.version println "java.library.path: " + System.properties["java.library.path"] def localhost = InetAddress.getLocalHost() println hostName = localhost.getHostName()

xmlSlurper = new XmlSlurper() println xmlSlurper.class.getCanonicalName() println xmlSlurper.getClass().getPackage().getImplementationTitle() println xmlSlurper.getClass().getPackage().getImplementationVendor() println xmlSlurper.getClass().getPackage().getSpecificationVersion() println xmlSlurper.getClass().getPackage().getImplementationVersion() println xmlSlurper.class.getProtectionDomain().getCodeSource().getLocation().getPath() println xmlSlurper.class.getProperties().each { println it }

String manipulation

assert 'Groovy'.length() == 6 assert 'Groovy'.substring(3) == 'ovy' assert 'Groovy'.substring(0,2) == 'Gr' assert 'Groovy'.take(4) == 'Groo' assert 'GroovyDancing'[4..-1] == 'vyDancing' assert 'Groovy'.reverse().take(4).reverse() == 'oovy' assert 'Groovy'.replace('oo', 'a') == 'Gravy' assert 'Groovy'.take(3).replace('o', 'u') == 'Gru' assert 'Groovy'.replaceAll('o', 'a') == 'Graavy' assert 'Groovy'.toLowerCase() == 'groovy' assert 'Groovy'.toUpperCase() == 'GROOVY' assert 'groovy'.capitalize() == 'Groovy' assert 'grOOvy'.capitalize() == 'GrOOvy' assert 'grOOvy'.toLowerCase().capitalize() == 'Groovy' assert 'Groovy'.reverse() == 'yvoorG' assert 'Groovy'.count('o') == 2 assert 'Groovy'.contains('oo') == true assert 'o' in 'Groovy'.collect() == true //it works on Collection not String assert 'Groovy'.equals('Groovy') == true assert 'Groovy'.equalsIgnoreCase('gRoOvY') == true assert 'Groovy'.startsWith('Gr') assert 'Groovy'.endsWith('vy') assert 'Groovy'.isEmpty() == false assert 'Groovy'.indexOf('v') == 4 assert 'Groovy'.matches(/^Gr.*/) == true assert 'Groovy'.matches(/.*oo.*/) == true assert 'Groovy'.matches(/.*vy$/) == true assert 'Groovy'.split('r') == ['G', 'oovy'] assert 'Groovy'.padLeft(10, '*') == '****Groovy' assert 'Groovy'.padRight(10, '*') == 'Groovy****' assert 'Groovy'.center(10, '*') == '**Groovy**' assert 'Groovy' - 'o' == 'Grovy' assert 'Groovy' + 'Baby' == 'GroovyBaby' assert 'Groovy' * 2 == 'GroovyGroovy' assert ' Groovy '.trim() == 'Groovy' assert 'Groovy '.trim() == 'Groovy' assert ' Groovy'.trim() == 'Groovy'

def ltrim = { it.replaceAll(/^* /, '') } def rtrim = { it.replaceAll(/ *$/, '') } assert ltrim(' Groovy') == 'Groovy' assert rtrim('Groovy ') == 'Groovy'

String.metaClass.ltrim = { return delegate.replaceAll(/^* /, '') } String.metaClass.rtrim = { return delegate.replaceAll(/ *$/, '') } assert ' Groovy'.ltrim() == 'Groovy' assert 'Groovy '.rtrim() == 'Groovy' assert ' Groovy'.ltrim() == 'Groovy' assert 'Groovy '.rtrim() == 'Groovy'

assert 'Groovy'.matches(/.*[a-z].*/) == true assert 'Groovy'.matches(/.*[A-Z].*/) == true assert 'GROOVY'.matches(/.*[a-z].*/) == false assert 'groovy'.matches(/.*[A-Z].*/) == false

assert 'A sEnTeNcE'.toLowerCase().contains('t') == true assert 'A sEnTeNcE'.toUpperCase().contains('C') == true assert ['A', 'B', 'C']*.toLowerCase().contains('b') == true assert ['a', 'b', 'c']*.toUpperCase().contains('B') == true

assert 'GroovyBaby'.split("(?=\\p{Upper})").join(" ") == 'Groovy Baby' assert 'GroovyBaby'.split("(?=\\p{Lower})").join(" ") == 'G r o o v yB a b y' assert 'Best.Language.Ever'.split("(?=\\p{Punct})").join(" ") == 'Best .Language .Ever' assert 'Best,Language!Ever'.split("(?=\\p{Punct})").join(" ") == 'Best ,Language !Ever' assert 'Best.Language.Ever'.split("(?=\\p{Punct})").join(" ").toString().replaceAll("\\.", "") == 'Best Language Ever' //escape the fullstop

assert '05.00'.replaceAll(/^0/, '') == '5.00'

s = "A silly string with words"

assert s.capitalize() == 'A silly string with words'

groovy.grape.Grape.grab(group:'org.apache.commons', module:'commons-lang3', version:'3.3.2') assert org.apache.commons.lang3.text.WordUtils.capitalizeFully(s) == 'A Silly String With Words'

A side note about @Grab which you will see again further down: This annotation automatcally uses Ivy / Maven to get the jars you require,

and their dependencies. It can be a bit of a dark art to set up, but once it works, it works well. In theory, on a new install of Groovy, without a proxy,

this *should* work out of the box. I have it here for reference to the libs that are required, more than as a working example. YMMV.

assert s[0..9] == 'A silly st'

assert s.take(10) == 'A silly st' assert s.take(1) == 'A' assert s.take(100) == 'A silly string with words'

def (a, b) = [1, 2] assert b == 2

assert 'I love Groovy'.tokenize() == ['I', 'love', 'Groovy']

assert Math.round(15.8) == 16 assert Math.round(15.45555555555554) == 15 assert Math.round(0.123456789) == 0

import java.text.SimpleDateFormat now = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new Date()) println "now: ${now}" today = new SimpleDateFormat('yyyy-MM-dd').format(new Date()) println "today: ${today}" tenMinsAgo = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new Date(System.currentTimeMillis()-10*60*1000)) println "tenMinsAgo: ${tenMinsAgo}" halfHourAgo = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new Date(System.currentTimeMillis()-30*60*1000)) println "halfHourAgo: ${halfHourAgo}" hourAgo = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new Date(System.currentTimeMillis()-1*60*60*1000)) println "hourAgo: ${hourAgo}" dayAgo = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new Date(System.currentTimeMillis()-24*60*60*1000)) println "dayAgo: ${dayAgo}" yesterday = new SimpleDateFormat('yyyy-MM-dd').format(new Date(System.currentTimeMillis()-24*60*60*1000)) println "yesterday: ${yesterday}" twoDaysAgo = new SimpleDateFormat('yyyy-MM-dd').format(new Date(System.currentTimeMillis()-48*60*60*1000)) println "twoDaysAgo: ${twoDaysAgo}"

import groovy.time.TimeCategory import groovy.time.TimeDuration Date timeStart = new Date() //something you want to measure the duration of Date timeStop = new Date() TimeDuration duration = TimeCategory.minus(timeStop, timeStart) println "duration: ${duration}" println "duration in ms: ${duration.toMilliseconds()}" println "duration in seconds: ${duration.getSeconds()}" println "three seconds less duration in ms: ${3000 - duration.toMilliseconds()}" now = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new Date()) println now later = '2020-07-15 09:39:47' if (now < later) { println 'now < later' } else if (now > later) { println 'now > later' } duration = TimeCategory.minus(Date.parse('yyyy-MM-dd HH:mm:ss', later), Date.parse('yyyy-MM-dd HH:mm:ss', now)) println "duration: ${duration}" println "duration in ms: ${duration.toMilliseconds()}" println "duration in days: ${duration.getDays()}" println now.dump() println later.dump() println duration.dump()

Date date1 = Date.parse('dd-MMM-yyyy', '07-OCT-2018') newDate1 = date1.format('d-M-yyyy') assert newDate1 == '7-10-2018' Date date2 = Date.parse('dd MMM yy', '7 Oct 18') newDate2 = date2.format('d-M-yyyy') assert newDate2 == '7-10-2018' Date date3 = Date.parse('dd/MM/yy', '7/10/18') newDate3 = date3.format('d-M-yyyy') assert newDate3 == '7-10-2018'

Closures, ranges and other constructs

def squareIt = { int x -> square = x**2 return square } assert squareIt(5) == 25

def addUp = { int... varargs -> added = varargs.sum() return added } assert addUp(10, 11, 12) == 33

1.upto(4) { println "Number ${it}" } 3.times { println "Hello World ${it}" } 'Groovy'.collect { println 'letter:' + it } (1..10).collect { println it * 2 } (1..10).each { println ((it % 5 == 0) ? "${it} is a factor of 5" : "${it} is not a factor of 5") } ('a'..'f').eachWithIndex { it, index -> println "${it} is at position ${index + 1}" }

def range = (1..1000) as Integer[] assert range.sum() == 500500

def list = (1..10).collect()

for (i in list) { if (i < 6) { continue } println i }

list.each { if (it < 6) { return } println it }

list.each { try { def undef = 1.0 / 0 } catch(Exception e) { println "${e} caught for ${it}, but looping will continue" return } }

def urkel() { if ('a'.equals('a')) { return 'a' } else { return 'b' } } //or def elvis = ('a'.equals('a') ? 'a' : 'b') assert urkel() == 'a' assert elvis == 'a'

(1..100).each { println ( (it % 3 ? "" : "Fizz") + ( it % 5 ? "" : "Buzz") ?: it ) }

[ 's', '1000', '12.2', '15', 'A', '1', 'D', 'A.b', '12.', '.2'].each { if (it.contains(".") && it =~ /\d.*\.\d.*/) { // if it has a decimal and integers on either side println it.tokenize(".").sum { it.toInteger() } //add the two digits } }

[3, 4, 15, 16, 151694653, 1022].each { upToFour(it) } def upToFour(num) { while (num % 4 != 0) { num++ } println num }

def returnTwo() { def a = 1 def b = 2 return [a, b] } assert returnTwo() == [1, 2] println returnTwo().getClass() //or assert returnTwo().class == java.util.ArrayList //or assert returnTwo() instanceof java.util.ArrayList // we'll use this going forward

enum WeekdayColours { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday public static String getColour(WeekdayColours day) { String colour = null switch(day) { case Monday: colour = 'GREEN'; break case Tuesday: colour = 'YELLOW'; break case Wednesday: colour = 'GREY'; break case Thursday: colour = 'BLUE'; break case Friday: colour = 'BROWN'; break case Saturday: colour = 'BLACK'; break case Sunday: colour = 'WHITE'; break default: println "Something else" } return colour } } a = WeekdayColours.Friday assert WeekdayColours.getColour(a) == 'BROWN'

//lists to keep the thread instances List threads1 = [] List threads2 = [] //first task (e.g. putting on Q) def doThis = { i, j -> sleep(randNum(100)) println "doThis(${i}) thread: ${j}" } //second task (e.g. getting from Q) def doThat = { i, j -> sleep(randNum(20000)) println "doThat(${i}) thread: ${j}" } //call first task (e.g. for eachRow from DB, put msg on Q) 20.times { i -> t1 = Thread.start { doThis(i, t1.name) } threads1.add(t1) } //wait for all task 1 threads to end for (thread in threads1) { thread.join() println "doThis joined: ${thread.name}" } //call second task (e.g. for each correlation ID, get msg from Q) 20.times { i -> t2 = Thread.start { doThat(i, t2.name) } threads2.add(t2) } //wait for all task 2 threads to end for (thread in threads2) { thread.join() println "doThat joined: ${thread.name}" } println "all done"

Collection iteration

Lists

[1, 2, 3, 4, 5, 6, 7, 8, 9].each { println it * 2 } [1, 2, 3, 4, 5, 6, 7, 8, 9].each { i -> if ( i % 2 == 0 ) { println i * 2 } }

li = [14, 12, 35, 22, -5, 46, 98, 53, 29, 87, 44] assert li instanceof java.util.ArrayList assert li[0] == 14 assert li[-1] == 44 assert li.getAt(1) == 12 assert li.get(1) == 12 assert li.getAt(-1) == 44 assert li.count(12) == 1 assert li.intersect([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]) == [22, 29]

li.set(1, 88) assert li.getAt(1) == 88 li.set(1, 12) assert li.get(1) == 12 assert li.size() == 11 assert li.min() == -5 assert li.max() == 98 assert li.sum() == 435

List.metaClass.avg = { return delegate.size() ? delegate.sum() / delegate.size() : 0 } assert li.avg() == 39.5454545455

assert li.join("|") == '14|12|35|22|-5|46|98|53|29|87|44' assert li.find { it > 97 } == 98 assert li.find { it.toString() =~ /^4.*/ } == 46 assert li.findAll { it.toString() =~ /^4.*/ } == [46, 44] assert (li.contains(35)) ? 'yes' : 'no' == 'no' assert li.findAll { it < 15 } == [14, 12, -5] assert li.findIndexOf{ it == 12 } == 1 assert li.contains(13) == false assert li.isEmpty() == false li2 = li li2.addAll([7, 32]) assert li2 == [14, 12, 35, 22, -5, 46, 98, 53, 29, 87, 44, 7, 32] li2.removeElement(-5) assert li2.sort() == [7, 12, 14, 22, 29, 32, 35, 44, 46, 53, 87, 98] assert li2.reverse() == [98, 87, 53, 46, 44, 35, 32, 29, 22, 14, 12, 7]

li3 = ['i', 'l', 'o', 'v', 'e', 'g', 'r', 'o', 'o', 'v', 'y'] assert li3.each { it } == ['i', 'l', 'o', 'v', 'e', 'g', 'r', 'o', 'o', 'v', 'y'] assert li3.toSorted().each { it } == ['e', 'g', 'i', 'l', 'o', 'o', 'o', 'r', 'v', 'v', 'y'] assert li3.toUnique().each { it } == ['i', 'l', 'o', 'v', 'e', 'g', 'r', 'y'] assert li3.toSorted().toUnique().each { it } == ['e', 'g', 'i', 'l', 'o', 'r', 'v', 'y']

li4 = ['I', 'l', 'o', 'V', 'e', 'G', 'r', 'o', 'O', 'v', 'y'] assert li4.each { it } == ['I', 'l', 'o', 'V', 'e', 'G', 'r', 'o', 'O', 'v', 'y'] assert li4.toSorted().each { it } == ['G', 'I', 'O', 'V', 'e', 'l', 'o', 'o', 'r', 'v', 'y'] assert li4.toUnique().each { it } == ['I', 'l', 'o', 'V', 'e', 'G', 'r', 'O', 'v', 'y'] assert li4.toSorted().toUnique().each { it } == ['G', 'I', 'O', 'V', 'e', 'l', 'o', 'r', 'v', 'y']

assert li4.sort{it.toLowerCase()} == ['e', 'G', 'I', 'l', 'o', 'o', 'O', 'r', 'V', 'v', 'y'] assert li4.sort{it.toUpperCase()}.toUnique() == ['e', 'G', 'I', 'l', 'o', 'O', 'r', 'V', 'v', 'y'] assert li4.sort{it.toUpperCase()} == ['e', 'G', 'I', 'l', 'o', 'o', 'O', 'r', 'V', 'v', 'y'] assert li4.sort{it.toUpperCase()}.toUnique() == ['e', 'G', 'I', 'l', 'o', 'O', 'r', 'V', 'v', 'y']

li5 = ['Blinky', 'Pinky', 'Inky', 'Clyde'] li5.each { i -> //use if statement else you'll get an error if there's no match def m = i =~ /^(C.*)/ //brackets around the match object you want to capture if (m) { assert m[0][1] == 'Clyde' } //first capture in match } li5.each { i -> def m = i =~ /(.*e)$/ if (m) { assert m[0][1][3] == 'd' } //fourth element of capture }

li6 = ['a', 'a', 'b', 'c', 'd', 'e', 'e'] li7 = ['a', 'b', 'c', 'd', 'e', 'f'] def overlaps = li6.intersect(li7) assert overlaps == ['a', 'b', 'c', 'd', 'e']

def combo = li6.plus(li7) assert combo == ['a', 'a', 'b', 'c', 'd', 'e', 'e', 'a', 'b', 'c', 'd', 'e', 'f']

def diff = li7.minus(li6) //removes all occurences of element ! assert diff == ['f']

def literalDiff = [] li6.each { if (li6.count(it) > 1) { literalDiff.add(it) } } assert literalDiff == ['a', 'a', 'e', 'e']

def duplicates = li6.findAll { x -> li6.findAll { y -> y == x }.size() > 1 }.unique() assert duplicates == ['a', 'e']

def (passed, failed) = [39, 56, 67, 76, 82, 89, 91].split{ it > 60 } // or println ([39, 56, 67, 76, 82, 89, 91].groupBy { it > 60 ? true : false })

Maps

m = [sky:'blue', grass:'green', ocean:'blue', ground:'brown', sun:'yellow'] assert m['grass'] == 'green' assert m.get('ocean') == 'blue' assert m.size() == 5 m.put('night', 'black') assert m['night'] == 'black' assert m.size() == 6 m.remove('sun') assert m.size() == 5 m.each { key, value -> if (key.startsWith("gr")) println value } def found = m.find{ it.key == "sky" }?.value assert found.equals("blue") assert found instanceof java.lang.String def allFound = m.findAll{ key, value -> key.startsWith('gr') } assert allFound == ([grass:'green', ground:'brown']) assert allFound instanceof java.util.HashMap def allFoundRegex = m.findAll{ key, value -> key.matches(/^gr.*/) } assert allFoundRegex == ([grass:'green', ground:'brown'])

map = ['02.00':2, '06.00':6, '01.00':1, '04.00':4, '05.00':5, '03.00':3] println map.sort { -it.value }

inv = ['telephone':'Bell', 'aeroplane':'Wright', 'lightbulb':'Edison',\ 'penicillin':'Pasteur', 'pi':'Archimedes', 'electricity':'Franklin', 'telegraph':'Morse']

assert inv['pi'] == 'Archimedes' assert inv.get('pi') == 'Archimedes'

assert inv.find { it.value == 'Wright' }?.key == 'aeroplane'

assert inv.containsKey('pi') == true assert inv.containsValue('Archimedes') == true

def msl = [:] def li8 = ['a', 'b', 'c', 'd', 'e'] def li9 = ['f', 'g', 'h', 'i', 'j'] def li10 = ['k', 'l', 'm', 'n', 'o'] msl.'1'= li8 assert msl.'1'[0] == 'a' println msl.'1'[1] msl.each { k, v -> println v[2] } msl.'2' = li9 msl.'3' = li10

Iterator<Map.Entry<String, List>> iter = msl.iterator() iter.each { i -> println "key: ${i.getKey()} val: ${i.getValue()} last list item: ${i.getValue()[-1]}" }

Random numbers and strings

def randStr() { //random size return new Random().with { (1..(Math.abs(new Random().nextInt() % 5) + 1)) .collect { (('A'..'Z')+('0'..'9')+('a'..'z')) .join()[ nextInt( (('A'..'Z')+('0'..'9')+('a'..'z')) .join().length() ) ] } .join() } } def randNum() { //random size return Math.abs(new Random().nextInt() % (Math.abs(new Random().nextInt()))) + 1 } def randStr(desiredSize) { return new Random().with { (1..desiredSize) .collect { (('A'..'Z')+('0'..'9')+('a'..'z')) .join()[ nextInt( (('A'..'Z')+('0'..'9')+('a'..'z')) .join().length() ) ] } .join() } } def randNum(maxSize) { return Math.abs(new Random().nextInt() % maxSize) + 1 } println "random string: ${randStr()}" println "random number: ${randNum()}" println "random string of 10 characters: ${randStr(10)}" println "random number between 1 and 3: ${randNum(3)}" println "random number between 1 and a million: ${randNum(1000000)}"

Filesystem interaction

def myFile = new File("./src/myfile.txt") myFile.write("Hello from Groovy

") //overwrites existing file myFile << "More text

" // appends myFile.append("Last line") assert myFile.text instanceof java.lang.String println myFile.text println myFile.text.size() assert myFile.readLines() instanceof java.util.ArrayList println myFile.readLines().size()

File fileObject = new File("${this.class.getName()}.groovy") println fileObject.name println fileObject.absolutePath

testDate = new SimpleDateFormat('yyyy-MM-dd HH-mm').format(new Date()) def logFile = new File("./src/log-${testDate}.txt")

new File('.').eachFileRecurse { file -> println "On ${new Date(file.lastModified()).format('EEE MMM dd hh:mm:ss a yyyy')} ${file.name} was modified" }

import static groovy.io.FileType.FILES List li = [] new File('.').eachFileRecurse(FILES) { f -> if(f.name.endsWith('.groovy')) { println "file name ${f} found" f.readLines().each { l -> if (l.startsWith("import")) { println "found import: ${l}" li.add(l) } } } } li.sort().unique().each { i -> println i }

new File("./src/sorted.txt").write(new File("./src/unsorted.txt").with { it.text = it.readLines().findAll { it }.sort().unique().join('

') })

new File("./src/siteSnippetsV5.groovy").eachLine { line -> assert line instanceof java.lang.String assert line.length() instanceof java.lang.Integer }

List listFileContents = new File('./src/siteSnippetsV5.groovy').collect { it } assert listFileContents instanceof java.util.ArrayList println listFileContents.size()

index = 0 def elementLength = listFileContents[0].length() listFileContents.eachWithIndex { element, index -> if (listFileContents[index].length() > elementLength) { elementLength = listFileContents[index].length() } } println "${listFileContents[index]} is the longest line in the file"

groovy.grape.Grape.grab(group:'org.apache.ant', module:'ant', version:'1.9.8') groovy.grape.Grape.grab(group:'org.apache.ant', module:'ant-launcher', version:'1.9.8') def ant = new AntBuilder() def file = new File(ant.project.baseDir,"src/myfile.txt") assert file.exists() ant.replace(file: file, token: ", );", value: ");") ant.mkdir(dir: "../backup") ant.copy( todir:"../backup" ) { fileset( dir:"./src/" ) } def zipfile = '../backup/backup.zip' def current = './src' ant.zip(destfile: zipfile) { fileset(dir: current) { include(name: '**/*.*') } } ant.delete(dir:'../backup',failonerror:false)

new File("src/data.csv").splitEachLine(",") { line -> println "FirstName: ${line[0]}; LastName: ${line[1]}" }

groovy.grape.Grape.grab(group:'com.opencsv', module:'opencsv', version:'4.5') groovy.grape.Grape.grab(group:'com.xlson.groovycsv', module:'groovycsv', version:'1.3') import static com.xlson.groovycsv.CsvParser.parseCsv for(line in parseCsv(new FileReader('./src/data.csv'), separator: ',')) { println "$line.FirstName $line.LastName" }

Handling xml

HTML's handling of xml - not so poetic, if the display of this XML breaks in your browser, I'm sorry... here it is in a file

def myXmlString = '''

68246894 Huey 15778047 899 68246895 Dewey 16288 120 68246896 Louie 89257067 210 68246897 Dewey 123321 500

'''

def transaction = new XmlSlurper().parseText(myXmlString)

assert transaction.payment.txAmount[0] == '899' assert transaction.payment.accountNo.@type[1] == 'Savings' assert transaction.payment[2].accountNo.@type == 'Cheque' assert transaction.receipt[0].txID == '68246895'

transaction.payment.findAll { tx -> tx.txAmount.toInteger() > 300 }.each { tx -> println "${tx.customerName} made payment of ${tx.txAmount} with transaction id ${tx.txID}." }

def accNos = { node -> node.text() } def validAccTypes = { node -> node.@type in ['Current', 'Cheque'] } //descends to lowest node println transaction.depthFirst().findAll(validAccTypes).collect(accNos) //equivalent of: println transaction.'**'.findAll(validAccTypes).collect(accNos) //only iterates first generation child nodes println transaction.children().findAll(validAccTypes).collect(accNos) //equivalent of: println transaction.'*'.findAll(validAccTypes).collect(accNos) //descends to lowest node, one parent node at a time println transaction.breadthFirst().findAll(validAccTypes).collect(accNos)

transaction.payment[1].customerName = 'Bob' def stringWriter = new StringWriter() println groovy.xml.XmlUtil.serialize(transaction)

transaction.receipt[0].replaceNode{ receipt(receiptNo:"65413"){ receiptdate("2018-09-30") customerName("Dewey") accountType("Current") accountNo("16288") txAmount("120") } } println groovy.xml.XmlUtil.serialize( transaction )

def newTransaction = new XmlParser( false, true ).parseText( myXmlString ) newValue = " <receiptDate>2018-09-30</receiptDate>" newNode = new XmlParser( false, true ).parseText( newValue ) newTransaction.'**'.find { it.name() == 'receipt' }.children().add( 2, newNode ) println groovy.xml.XmlUtil.serialize( newTransaction )

newTransaction.NameValuePairs.NameValuePair.findAll { it.name.text() == 'accountNo' }*.replaceNode{} println groovy.xml.XmlUtil.serialize( newTransaction )

import groovy.util.XmlSlurper import groovy.util.slurpersupport.GPathResult def transactions = new XmlSlurper().parseText(myXmlString) def leaves = transactions.depthFirst().findAll { it.children().size() == 0 } def path(GPathResult node) { def result = [node.name()] def pathWalker = [hasNext: { -> node.parent() != node }, next: { -> node = node.parent() }] as Iterator (result + pathWalker.collect { it.name() }).reverse().join('/') } leaves.each { node -> println "${path(node)} = ${node.text()}" }

Database work

groovy.grape.Grape.grab(group:'mysql', module:'mysql-connector-java', version:'5.1.32') import groovy.sql.Sql def myDB = Sql.newInstance('jdbc:mysql://127.0.0.7:3306/employees', 'user1', 'pass1', 'com.mysql.jdbc.Driver')

def numberOfRecords = myDB.firstRow("select count(*) as count from employees.employees;") println "There are ${numberOfRecords.count} in the employees table"

println sql.firstRow("SELECT * FROM employees.employees;").keySet().collect().join(",")

myDB.eachRow("select first_name, last_name from employees.employees;"){ println "${it.first_name} ${it.last_name}" }

List listOfLists = [][] myDB.eachRow("select first_name, last_name, age from employees.employees;") { row -> List innerList = [] innerList.add(row.first_name) innerList.add(row.last_name) innerList.add(row.age.toString()) listOfLists.add(innerList) } listOfLists.each { li -> def first_name = li[0] def last_name = li[1] def age = li[2] // do something with it... }

myDB.execute("use employees;") myDB.executeUpdate("""update employees.employees set last_name = 'Bradford' where last_lame = 'Simmel' and first_name = 'Bezalel';""") myDB.executeInsert("""INSERT INTO `employees` VALUES (10000,'1960-10-01','Peter','Morgan','M','1995-02-10');""")

myDB.close()

The ? parameters is for JDBC to optimise the query by precompiling it with parameters. Always use it.

If you use "${}" gstrings in your query for variables, the SQL is not optimised by JDBC, and it will carp about it.

def insertEmployee(emp_no, birth_date, first_name, last_name, gender, hire_date) { def db = Sql.newInstance('jdbc:mysql://127.0.0.7:3306/employees', 'user1', 'pass1', 'com.mysql.jdbc.Driver') db.executeInsert("insert into employees VALUES (?, ?, ?, ?, ?, ?);", [emp_no, birth_date, first_name, last_name, gender, hire_date]) db.close() }

Sql.newInstance("""jdbc:jtds:sqlserver://SERVERNAME:1433/dbname; useLOBs=false; instance=SERVERNAME; autoCommit=true; useNTLMv2=true; domain=MYDOMAIN", "MyUser", "MyPassword", "net.sourceforge.jtds.jdbc.Driver""")

Graphing with charts

groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart-parent', version:'3.5.2', type:'pom') groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart', version:'3.5.2') import org.knowm.xchart.CategoryChart import org.knowm.xchart.CategoryChartBuilder import org.knowm.xchart.SwingWrapper import org.knowm.xchart.style.Styler.LegendPosition import org.knowm.xchart.BitmapEncoder import org.knowm.xchart.BitmapEncoder.BitmapFormat CategoryChart chartB = new CategoryChartBuilder().width(800) .height(600) .title("Score Histogram") .xAxisTitle("Score") .yAxisTitle("Number") .build() chartB.getStyler().setLegendPosition(LegendPosition.InsideNW) chartB.getStyler().setHasAnnotations(true) chartB.addSeries("test 1", [ 0, 1, 2, 3, 4 ], [ 4, 5, 9, 6, 5 ]) new SwingWrapper(chartB).displayChart() BitmapEncoder.saveBitmap(chart, "./src/Bar.png", BitmapFormat.PNG)

groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart-parent', version:'3.5.2', type:'pom') groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart', version:'3.5.2') import java.awt.Color import org.knowm.xchart.PieChart import org.knowm.xchart.PieChartBuilder import org.knowm.xchart.SwingWrapper import org.knowm.xchart.internal.chartpart.Chart import org.knowm.xchart.BitmapEncoder import org.knowm.xchart.BitmapEncoder.BitmapFormat PieChart chartP = new PieChartBuilder().width(800) .height(600) .title(getClass().getSimpleName()) .build() Color[] sliceColors = [ new Color(224, 68, 14), new Color(230, 105, 62), new Color(236, 143, 110), new Color(243, 180, 159), new Color(246, 199, 182) ] chartP.getStyler().setSeriesColors(sliceColors) chartP.addSeries("Gold", 24) chartP.addSeries("Silver", 21) chartP.addSeries("Platinum", 39) chartP.addSeries("Copper", 17) chartP.addSeries("Zinc", 40) new SwingWrapper(chartP).displayChart() BitmapEncoder.saveBitmap(chartP, "./src/Pie.png", BitmapFormat.PNG)

groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart-parent', version:'3.5.2', type:'pom') groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart', version:'3.5.2') import org.knowm.xchart.XYChart import org.knowm.xchart.XYChartBuilder import org.knowm.xchart.SwingWrapper import org.knowm.xchart.style.Styler.LegendPosition import org.knowm.xchart.style.Styler.TextAlignment import org.knowm.xchart.internal.chartpart.Chart import org.knowm.xchart.BitmapEncoder import org.knowm.xchart.BitmapEncoder.BitmapFormat List xData = new ArrayList () List yData = new ArrayList () for (int i = -3; i <= 3; i++) { xData.add(i) yData.add(Math.pow(10, i)) } XYChart chartL = new XYChartBuilder().width(800) .height(600) .title("Powers of Ten") .xAxisTitle("Power") .yAxisTitle("Value") .build() chartL.getStyler().setChartTitleVisible(true) chartL.getStyler().setLegendPosition(LegendPosition.InsideNW) chartL.getStyler().setYAxisLogarithmic(true) chartL.getStyler().setXAxisLabelRotation(45) chartL.getStyler().setXAxisLabelAlignment(TextAlignment.Right) chartL.getStyler().setXAxisLabelRotation(90) chartL.getStyler().setXAxisLabelRotation(0) chartL.addSeries('10^x', xData, yData) new SwingWrapper (chartL).displayChart() BitmapEncoder.saveBitmap(chartL, "./src/Line.png", BitmapFormat.PNG)

groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart-parent', version:'3.5.2', type:'pom') groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart', version:'3.5.2') import org.knowm.xchart.DialChart import org.knowm.xchart.DialChartBuilder import org.knowm.xchart.SwingWrapper import java.awt.Color DialChart chartD = new DialChartBuilder().width(800) .height(600) .title("Dial Chart") .build() chartD.addSeries("CPU", 0.9381, "93.81 %") double[] values = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.82, 0.84, 0.86, 0.88, 0.9, 1.0] String[] ticks = ["0", "30", "60", "90", "120", "150", "180", "210", "240", " ", " ", " ", " ", "270", "300"] chartD.getStyler().setAxisTickValues(values) chartD.getStyler().setAxisTickLabels(ticks) chartD.getStyler().setAxisTickLabelsVisible(true) chartD.getStyler().setAxisTicksMarksVisible(true) chartD.getStyler().setAxisTickMarksColor(Color.BLACK) chartD.getStyler().setArcAngle(320) chartD.getStyler().setGreenFrom(0) chartD.getStyler().setGreenTo(0.3) chartD.getStyler().setNormalColor(Color.YELLOW) chartD.getStyler().setNormalFrom(0.3) chartD.getStyler().setNormalTo(0.7) chartD.getStyler().setRedFrom(0.7) chartD.getStyler().setRedTo(1.0) chartD.getStyler().setDonutThickness(0.1) chartD.getStyler().setToolTipsEnabled(true) chartD.getStyler().setHasAnnotations(true) chartD.getStyler().setLegendVisible(true) new SwingWrapper (chartD).displayChart() BitmapEncoder.saveBitmap(chartD, "./src/Dial.png", BitmapFormat.PNG)

groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart-parent', version:'3.5.2', type:'pom') groovy.grape.Grape.grab(group:'org.knowm.xchart', module:'xchart', version:'3.5.2') import org.knowm.xchart.CategoryChart import org.knowm.xchart.CategoryChartBuilder import org.knowm.xchart.Histogram import org.knowm.xchart.SwingWrapper import org.knowm.xchart.style.Styler.LegendPosition CategoryChart chartS = new CategoryChartBuilder().width(800) .height(600) .title("Score Histogram") .xAxisTitle("Mean") .yAxisTitle("Count") .build() chartS.getStyler().setLegendPosition(LegendPosition.InsideNW) chartS.getStyler().setAvailableSpaceFill(0.96) chartS.getStyler().setOverlapped(true) histogram1 = new Histogram(getGaussianData(10000), 20, -20, 20) histogram2 = new Histogram(getGaussianData(5000), 20, -20, 20) chartS.addSeries("histogram 1", histogram1.getxAxisData(), histogram1.getyAxisData()) chartS.addSeries("histogram 2", histogram2.getxAxisData(), histogram2.getyAxisData()) private List getGaussianData(int count) { List data = new ArrayList (count) Random r = new Random() for (int i = 0; i < count; i++) { data.add(r.nextGaussian() * 10) } return data } new SwingWrapper (chartS).displayChart() BitmapEncoder.saveBitmap(chartS, "./src/StackedBar.png", BitmapFormat.PNG)

groovy.grape.Grape.grab(group:'com.kennycason', module:'kumo', version:'1.17', type:'pom') groovy.grape.Grape.grab(group:'com.kennycason', module:'kumo-core', version:'1.17') groovy.grape.Grape.grab(group:'com.kennycason', module:'kumo-api', version:'1.17') import static groovy.io.FileType.FILES import com.kennycason.kumo.CollisionMode import com.kennycason.kumo.WordFrequency import com.kennycason.kumo.WordCloud import com.kennycason.kumo.bg.RectangleBackground import com.kennycason.kumo.font.scale.LinearFontScalar import com.kennycason.kumo.nlp.FrequencyAnalyzer import java.awt.Dimension import java.awt.Color ofile = new File("./src/words.txt") ofile.write('') ["./src"].each { dir -> findWords(dir, ofile) } def findWords(dir, ofile) { new File(dir).eachFileRecurse(FILES) { if(it.name.endsWith('.groovy')) { //println it.name it.readLines().each { l -> if (! l.contains("//")) { w = l.split() w.each() { word -> if (! [ "//", "\\", '=', '==', '{', '}', '[', ']', '->', '|', '>=', '<=', '>', ' wordFrequencies = frequencyAnalyzer.load("./src/words.txt") Dimension dimension = new Dimension(600, 600) WordCloud wordCloud = new WordCloud(dimension, CollisionMode.RECTANGLE) wordCloud.setPadding(0) wordCloud.setBackground(new RectangleBackground(dimension)) wordCloud.setFontScalar(new LinearFontScalar(10, 40)) wordCloud.build(wordFrequencies) wordCloud.writeToFile("./src/wordcloud.png")

Bonus level