Wednesday, March 1, 2017

Powermock hints

In case you would like to mock some method in following way.
1) For input "A" method should return some specific answer "a"
2) For all other cases method sould return some default answer "default"

mockStatic(SomeClass.class);
when(SomeClass.fooBar(anyString())).thenReturn("default");
when(SomeClass.fooBar("A")).thenReturn("a");

It's abit uncommon way. I assumed that declaration should be vice versa, but it's not.

P.S. If you whant to verify also inputs, please refer to this article
http://stackoverflow.com/questions/12295891/how-to-use-argumentcaptor-for-stubbing 

Friday, May 20, 2016

JEEConf 2016 - Day 1

First impressions.

Environment
Place for conference is much better than we had last year. Now trip from stage to stage takes no more than one minute. It's very good for those who chose wrong talk.

Lunch in boxes is a cool idea. No queues for lunch at all this time. However portions are abit smaller. But you can take some extra snacks anywhere, so it's not a minus.

Speeches
There where interesting and not interesting speeches for me. I've got great insights regarding Spark and Scala. BigData processing is mainstream now.

Also speech about JUnit 5 was very interesting. I believe I've got whole idea of JUnit 5. Alot of valuable things coming there.

Entertaiments from sponcors
Not as much as last year.

This day buzzwords

spark, scala, kotlin

Saturday, March 5, 2016

Gradle plugin development and TDD


Gradle plugin development and TDD

I Getting started with environment
A) Setting up an environment
  1. install gradle 2.10+
  2. install gradle plugin for eclipse (  Gradle IDE    3.7.2.201511260851-RELEASE    org.springsource.ide.eclipse.gradle.feature.feature.group    Pivotal Software, Inc.)
  3. install groovy 2.4 support for eclipse from here (update site: http://dist.springsource.org/snapshot/GRECLIPSE/e4.4/)

B) Configure plugin project (code snippet for project)


// Write the plugin's classpath to a file to share with the tests
task createClasspathManifest {
        def outputDir = file("$buildDir/$name" )

       inputs.files sourceSets.main .runtimeClasspath
       outputs.dir outputDir

       doLast {
              outputDir.mkdirs()
              file( "$outputDir/plugin-classpath.txt" ).text = sourceSets.main .runtimeClasspath.join("\n")
       }
}

dependencies {
       compile 'org.codehaus.groovy:groovy:2.4.4'
       compile gradleApi()
       testCompile gradleTestKit()
       testCompile( 'com.netflix.nebula:nebula-test:4.0.0')
       testRuntime files(tasks.createClasspathManifest)
}

To create plugin in project create class that implements Plugin class

package my.great.pkg

import org.gradle.api.Plugin
import org.gradle.api.Project

class MyGreatPlugin  implements Plugin<Project> {
       
        @Override
        void apply(Project prj) {

Then register this class as a plugin by adding property file i.e. 'my-super-plugin.properties' (see below) to resources/META-INF/gradle-plugins
implementation-class=my.great.pkg.MyGreatPlugin 

After that you may use your plugin by declaring
                     plugins {
                           id 'my-super-plugin'
                     }
C) Write BaseSpec for your plugin
BaseSpec prepares settings file build file and plugin classpath

public class BaseSpec extends Specification{
       
        @Rule final TemporaryFolder testProjectDir = new TemporaryFolder()
       File buildFile
       File settingsFile
       List<File> pluginClasspath
       
        def setup() {
               settingsFile = testProjectDir .newFile('settings.gradle')
              
               buildFile = testProjectDir .newFile('build.gradle')
              
               pluginClasspath = preparePluginClassPath()
       }

        private List<String> preparePluginClassPath() {
               def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt" )
               if (pluginClasspathResource == null) {
                      throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.")
              }

              pluginClasspathResource. readLines().collect { new File(it ) }
       }


}

D) Write a speck for plugin (Only new notation works fine in tests)
Write whatewer you like instead of foo-bar

class MySuperPluginSpec extends BaseSpec {
       
        def setup() {
               buildFile << """
                     plugins {
                           id 'java'
                           id 'my-super-plugin'
                     }

                     version = '0.1.0'
                     group = 'foo.bar'
              """ .stripIndent ()

               settingsFile << """rootProject.name = 'foo-bar'""" .stripIndent ()
       }
Build file should contains everything you need in real build file with this project
Also you may need some sample source files and resources. Here is the sample below
        private void createHelloWorld() {
               def src = new File(testProjectDir .folder , 'src/main/java/example')
              src.mkdirs()
              
               new File(src, 'HelloWorld.java').text = '''\
              package example;
              
              /**
              * HelloWorld class for test
              *
              * @copyright.placeholder@
              */
              public class HelloWorld {
              }
              ''' .stripIndent ()
              
               def resources = new File(testProjectDir. folder, 'src/main/resources' )
              resources.mkdirs()
              
               new File(resources, 'foobar.properties').text = '''\
              # some comments
              * @copyright.placeholder@
              useful text
              ''' .stripIndent ()
       }

Let's do the test itself.
Given section: We created sample files for project.
When section: We launched gradle build and got result in variable result. !If you expect build to fail, please 
Than section: We evaluate result and task outputs itself

        def 'sources jar is created'() {

              given:
                     createHelloWorld();

              when:
                      def result
                     result = GradleRunner. create()
                                                .withProjectDir( testProjectDir.root)
                                                .withArguments( 'sourcesJar')
                                                .withPluginClasspath( pluginClasspath)
                                                .forwardOutput()
                                                .build() //

              then:
                     result.task( ":sourcesJar").outcome == SUCCESS //import static org.gradle.testkit.runner.TaskOutcome.*
                     File resultJar= new File(testProjectDir .root, 'build/libs/test-0.1.0-sources.jar' )
                     resultJar.exists()

                     AntBuilder ant = new AntBuilder();
                     ant. unzip src:"$resultJar.canonicalPath",
                                          dest:"$ testProjectDir.root/unpacked",
                                          overwrite:"true" )

                     File helloWorldHtml= new File(testProjectDir .root, "unpacked/example/HelloWorld.java" );
                      assertThat(helloWorldHtml, containsString('Some copyright'));
       }

If you would like to check up what's going on in project folder (temp folder is erased after test run), you may do like this:

                     AntBuilder ant = new AntBuilder();
                     
                     ant.zip(destfile: 'C:/temp_2/test.zip',
                            basedir: "$testProjectDir.root" )

II Plugin interaction with your build script
A) Things to keep in mind
Plugin take information from your build script using extensions (it's BEANS!!!) and add custom tasks to your build script.
So in case your plugin doesn't need own configuration => you don't need 

Plugins add their own tasks. So your plugin will do the same. Even if it's internal task. It's visible. (They need to have group 'build')

Tasks may not (and will not) be executed in order you declared them in apply block. Use dependsOn and executeAfter allways.

Keep in mind that gradle "understands" that task shall or shall not be executed by evaluating task outcomes (???)

B) Prepare task for launch
In apply section you create new task object with corresponding name. Than you may want to configure task with some specific settings. There are two cases B.1 - You use your own configuration B.2 - You tries to reuse existing one

B.1) Your own shiny configuration
Here is how it looks like in build script
                           myconfig {
                                  user="ADMIN"
                                  password="secret"
                           }
Let's get it in the plugin.
     1] Define your own extension (package doesn't mater and keep in mind it's still groovy, not java)
class MyPluginExtension {
       String user;
       String password;
}
     2] Get this configuration in plugin code
              project.extensions.create( 'myconfig', MyPluginExtension)
              
               MyPluginExtension myConfigFromBuildScript = project.extensions.myconfig
              
               //create your task
               MyTask task = new MyTask();
              
              project.afterEvaluate {
                     task.user = myConfigFromBuildScript.user
                     task.password = myConfigFromBuildScript.password
              }
B.1) You tries to reuse existing one. 
Let's work with jar.manifest configuration. I would like to define there some fields in case they are not defined inside build script.
              project.jar {
                      manifest {
                            attributes  'Implementation-Vendor': 'Me, Serhii Belei',
                           'Build-date' : new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
                     }
              }
C) How to create new task
Usually you have to do it in apply section
              project.tasks.create( "yourTaskName", Exec) {//or Jar or Copy
                      dependsOn project.tasks.getByName('otherTaskName')
                      group 'build'//or documentation or whatever
                      description "Human readable desription of the task"
                         ...
              }
D) How to override existing task
Please pay attention to another syntax of task creation
              project.tasks.create( name: 'processResources', type : Copy, overwrite : true) {
                      into (project.sourceSets.main.output.resourcesDir)
                      from (project.sourceSets.main.resources) {
                            filter(...)
                     }
              }

E) How to rework snippet from build script into plugin

  1. add project. variable before file; dependencies; configurations; etc
            @Override
            public void apply(Project prj) {
                  prj.apply plugin: WarPlugin
                  prj.dependencies {
                          compile prj.fileTree(
  2. Use project.beforeEvaluate and project.afterEvaluate
                  prj.afterEvaluate {
                         prj.eclipse {
                                classpath {
  3. Local pathes like "my/path" replace with "${project.buildDir}/my/path"
    into "${project.buildDir}/tmp/someFolder"

E) Read source code in gradle folder and source code of other plugins
%GRADLE_HOME%/src/plugins (the best way is to open it with Intellij IDEA community edition)

Saturday, January 25, 2014

What Ukrainians are fighting for

You may notice avatars like this. Why?

Our Ukrainian parliament in illegal way accepted set of laws that kills democracy in Ukraine. These laws forbid us to make peaceful protests, use internet without censorship and so on. Russian parliament accepted the same laws beforehand.  Parliament did it in illegal way, so it's outside the law now and it has to be changed.

According to our laws our President guarantees that none of the laws change constitution. Our President signed laws that are wrong according to our constitution and Human Rights. He didn't do his job well and he should quit.

Our police used force against peaceful demonstration. Now police use tortures against people who was arrested. Responsible persons has to be found and judged.

Ukrainians love democracy and freedom. Pylyp Orlyk was a Ukrainian (http://en.wikipedia.org/wiki/Pylyp_Orlyk). So freedom and democracy what we are fighting for. We don't get it from Russia because Russia doesn't have one. We need our democracy.

Europe and US. Please understand that "All that is necessary for the triumph of evil is that good men do nothing".
The only thing necessary for the triumph of evil is for good men to do nothing.

Read more at http://www.brainyquote.com/quotes/quotes/e/edmundburk377528.html#rEWB2R8GcDrscfc7.99
The only thing necessary for the triumph of evil is for good men to do nothing.

Read more at http://www.brainyquote.com/quotes/quotes/e/edmundburk377528.html#rEWB2R8GcDrscfc7.99
The only thing necessary for the triumph of evil is for good men to do nothing.

Read more at http://www.brainyquote.com/quotes/quotes/e/edmundburk377528.html#rEWB2R8GcDrscfc7.99
The only thing necessary for the triumph of evil is for good men to do nothing.

Read more at http://www.brainyquote.com/quotes/quotes/e/edmundburk377528.html#rEWB2R8GcDrscfc7.99
The only thing necessary for the triumph of evil is for good men to do nothing.

Read more at http://www.brainyquote.com/quotes/quotes/e/edmundburk377528.html#rEWB2R8GcDrscfc7.99

Monday, October 7, 2013

GitDetails plugin for Total Commander

During two evenings (Saturday and Monday) I made plugin for Total Commander. This plugin is based on java plugin interface (by Ken Händel) located here http://www.totalcmd.net/plugring/tc_java.html.

All source code you may find at my github https://github.com/crc83/tc-git-plugin
Binary distribution you may create by running mvn assembly, or download from here: https://github.com/crc83/tc-git-plugin/blob/master/binary/GitDetails-1.0.zip

Please contact me if you would like to see more features in this plugin. 

Thursday, September 12, 2013

Intellij Idea task repository plugin creation

Key notes
1) Reuse existing infrastructure
@Tag("Rally") // This is name of part in xml configuration file where your settings will be stored
public class RallyRepository extends BaseRepositoryImpl {

public class RallyRepositoryType extends BaseRepositoryType<RallyRepository> {
// UI things are located here (repository name, icon and stuff)

public class RallyTask extends Task {
// It's all about tasks. But nothing special here. Just implement all methods carefully

META-INF/plugin.xml
// In this file you may find some plugin configuration. But there is also nothing special

Making all the stuff works
All configuration goes through repository deitor which is responsible for reading changing and storing configuration. So extend existing one:

public class RallyRepositoryEditor extends BaseRepositoryEditor<RallyRepository> {

What is necesary to understand before implementation is that editor is tightly coupled with repository itself. Main items:
1) Editor check if something changed via equals method of repository (In our case RallyRepository)
2) Editor uses copying constructor of repository to create new changed instance of it
3) Editor serializes and deserializes repository according to bean conventions by default, so don't forget about appropriate getters and setters
4) Also don't use getXXX and setXXX methods for fields you don't whant to serialize. (There is @Transient annotation and you can use it)
5) Don't invoke logger in constructior of repository

You may refer my own plugin at github for additional implementation details (https://github.com/crc83/rallydev). I changed a lot from one that I forked (https://github.com/RallySoftware/intellij-plugin).

Download ready to use jar you can from here (http://dl.bintray.com/crc83/generic/rallydev.zip).