Git Product home page Git Product logo

aibolit's Introduction

PyPi version Build Status Build status Hits-of-Code Test Coverage Maintainability License

How it works?

Learn how Aibolit works in our White Paper.

How to use ?

First, you install it (you must have Python 3.7.7 and Pip installed):

$ pip3 install aibolit

To analyze your Java sources, located at src/java (for example), run:

$ aibolit check --filenames src/java/File.java src/java/AnotherFile.java

or

$ aibolit recommend --filenames src/java/File.java src/java/AnotherFile.java

Also, you can set a folder with Java files:

$ aibolit recommend --folder src/java

It will run recommendation function for the model (model is located in aibolit/binary_files/model.pkl. The model finds a pattern which contribution is the largest to the Cyclomatic Complexity. If anything is found, you will see all recommendations for the mentioned patterns. You can see the list of all patterns in Patterns.md. The output of recommendation will be redirected to the stdout. If the program has the 0 exit code, it means that all analyzed files do not have any issues. If the program has the 1 exit code, it means that at least 1 analyzed file has an issue. If the program has the 2 exit code, it means that program crash occurred.

You can suppress certain patterns (comma separated value) and they will be ignored. They won't be included into the report, also their importance will be set to 0.

$ aibolit recommend --folder src/java --suppress=P12,P13

You can change the format, using the --format parameter. The default value is --format=compact.

$ aibolit recommend --folder src/java --format=compact --full

It will output sorted patterns by importance in descending order and grouped by a pattern name:

Show all patterns
/mnt/d/src/java/Configuration.java score: 127.67642529949538
/mnt/d/src/java/Configuration.java[3840]: Var in the middle (P21: 30.95612931128819 1/4)
/mnt/d/src/java/Configuration.java[3844]: Var in the middle (P21: 30.95612931128819 1/4)
/mnt/d/src/java/Configuration.java[3848]: Var in the middle (P21: 30.95612931128819 1/4)
/mnt/d/src/java/Configuration.java[2411]: Null Assignment (P28: 10.76 2/4)
/mnt/d/src/java/Configuration.java[826]: Many primary constructors (P9: 10.76 3/4)
/mnt/d/src/java/Configuration.java[840]: Many primary constructors (P9: 10.76 3/4)
/mnt/d/src/java/Configuration.java[829]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[841]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[865]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[2586]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[3230]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[3261]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[3727]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[3956]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/ErrorExample.java: error when calculating patterns: Can't count P1 metric:
Total score: 127.67642529949538

(P21: 30.95612931128819 1/4) means the following:

30.95612931128819 is the score of this pattern
1 is the position of this pattern in the total list of patterns found in the file
4 is the total number of found patterns

You can use format=long. In this case all results will be sorted by a line number:

Show all patterns
/mnt/d/src/java/Configuration.java: some issues found
/mnt/d/src/java/Configuration.java score: 127.67642529949538
/mnt/d/src/java/Configuration.java[826]: Many primary constructors (P9: 10.76 3/4)
/mnt/d/src/java/Configuration.java[829]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[840]: Many primary constructors (P9: 10.76 3/4)
/mnt/d/src/java/Configuration.java[841]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[865]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[2411]: Null Assignment (P28: 10.76 2/4)
/mnt/d/src/java/Configuration.java[2586]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[3230]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[3261]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[3727]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/Configuration.java[3840]: Var in the middle (P21: 30.95612931128819 1/4)
/mnt/d/src/java/Configuration.java[3844]: Var in the middle (P21: 30.95612931128819 1/4)
/mnt/d/src/java/Configuration.java[3848]: Var in the middle (P21: 30.95612931128819 1/4)
/mnt/d/src/java/Configuration.java[3956]: Partial synchronized (P14: 0.228 4/4)
/mnt/d/src/java/ErrorExample.java: error when calculating patterns: Can't count P1 metric:
/mnt/d/src/java/MavenSlice.java: your code is perfect in aibolit's opinion
Total score: 127.67642529949538

You can also choose xml format. It will have the same format as compact mode, but xml will be created:

<report>
  <score>127.67642529949538</score>
  <!--Show all patterns-->
  <files>
    <file>
      <path>/mnt/d/src/java/Configuration.java</path>
      <summary>Some issues found</summary>
      <score>127.67642529949538</score>
      <patterns>
        <pattern code="P13">
          <details>Null check</details>
          <lines>
            <number>294</number>
            <number>391</number>
          </lines>
          <score>30.95612931128819</score>
          <order>1/4</order>
        </pattern>
        <pattern code="P12">
          <details>Non final attribute</details>
          <lines>
            <number>235</number>
          </lines>
          <score>10.76</score>
          <order>2/4</order>
        </pattern>
          <pattern code="P21">
          <details>Var in the middle</details>
          <lines>
            <number>235</number>
          </lines>
          <score>2.056</score>
          <order>3/4</order>
        </pattern>
          <pattern code="P28">
          <details>Null Assignment</details>
          <lines>
            <number>2411</number>
          </lines>
          <score>0.228</score>
          <order>4/4</order>
        </pattern>
      </patterns>
    </file>
    <file>
      <path>/mnt/d/src/java/ErrorExample.java</path>
      <summary>Error when calculating patterns: Can't count P1 metric: </summary>
    </file>
    <file>
      <path>/mnt/d/src/java/MavenSlice.java</path>
      <summary>Your code is perfect in aibolit's opinion</summary>
    </file>
  </files>
</report>

The score is the relative importance of the pattern (there is no range for it). The larger score is, the most important pattern is. E.g., if you have several patterns, first you need to fix the pattern with the score 5.45:

/mnt/d/src/java/SampleTests.java[43]: Non final attribute (P12: 5.45 1/10)
/mnt/d/src/java/SampleTests.java[44]: Non final attribute (P12: 5.45 1/10)
/mnt/d/src/java/SampleTests.java[80]: Var in the middle (P21: 3.71 2/10)
/mnt/d/src/java/SampleTests.java[121]: Var in the middle (P21: 3.71 2/10)
/mnt/d/src/java/SampleTests.java[122]: Var declaration distance for 5 lines (P20_5: 2.13 3/10)
/mnt/d/src/java/SampleTests.java[41]: Non final class (P24: 1.95 4/10)
/mnt/d/src/java/SampleTests.java[59]: Force Type Casting (P5: 1.45 5/10)
/mnt/d/src/java/SampleTests.java[122]: Var declaration distance for 7 lines (P20_7: 1.07 6/10)
/mnt/d/src/java/SampleTests.java[122]: Var declaration distance for 11 lines (P20_11: 0.78 7/10)
/mnt/d/src/java/SampleTests.java[51]: Protected Method (P30: 0.60 8/10)
/mnt/d/src/java/SampleTests.java[52]: Super Method (P18: 0.35 9/10)
/mnt/d/src/java/SampleTests.java[100]: Partial synchronized (P14: 0.08 10/10)
/mnt/d/src/java/SampleTests.java[106]: Partial synchronized (P14: 0.08 10/10)
/mnt/d/src/java/SampleTests.java[113]: Partial synchronized (P14: 0.08 10/10)

The score per class is the sum of all patterns scores.

/mnt/d/src/java/SampleTests.java score: 17.54698560768407

The total score is an average among all java files in a project (folder you've set to analyze)

Total average score: 4.0801854775508914

If you have 2 scores of different projects, the worst project is that one which has the highest score.

Model is automatically installed with aibolit package, but you can also try your own model

$ aibolit recommend --folder src/java --model /mnt/d/some_folder/model.pkl

You can get full report with --full command, then all patterns will be included to the output:

$ aibolit recommend --folder src/java --full

You can exclude files with --exclude command. You to set glob patterns to ignore:

$ aibolit recommend --folder src/java --exclude=**/*Test*.java --exclude=**/*Impl*.java

If you need help, run

$ aibolit recommend --help

How to retrain it?

Train command does the following:

  • Calculates patterns and metrics
  • Creates a dataset
  • Trains model and save it

Train works only with cloned git repository.

  1. Clone aibolit repository

  2. Go to cloned_aibolit_path

  3. Run pip install .

  4. Set env variable export HOME_AIBOLIT=cloned_aibolit_path (example for Linux).

  5. Set env variable TARGET_FOLDER if you need to save all dataset files to another directory.

  6. You have to specify train and test dataset: set the HOME_TRAIN_DATASET environment variable for train dataset and the HOME_TEST_DATASET environment variable for test dataset. Usually, these files are in scripts/target/08 directory after dataset collection (if you have not skipped it). But you can use your own datasets.

    Please notice, that if you set TARGET_FOLDER, your dataset files will be in TARGET_FOLDER/target. That is why it is necessary to set HOME_TRAIN_DATASET=TARGET_FOLDER\target\08\08-train.csv, HOME_TEST_DATASET =TARGET_FOLDER\target\08\08-test.csv

  7. If you need to set up own directory where model will be saved, set up also SAVE_MODEL_FOLDER environment variable. Otherwise model will be saved into cloned_aibolit_path/aibolit/binary_files/model.pkl

  8. If you need to set up own folder with Java files, use --java_folder parameter, the default value will be scripts/target/01 of aibolit cloned repo

Or you can use our docker image (link will be soon here)

Run train pipeline:

$ aibolit train --java_folder=src/java [--max_classes=100] [--dataset_file]

If you need to save the dataset with all calculated metrics to a different directory, you need to use dataset_file parameter

$ aibolit train --java_folder=src/java --dataset_file /mnt/d/new_dir/dataset.csv

You can skip dataset collection with skip_collect_dataset parameter. In this case the model will be trained with predefined dataset (see 5 point):

$ aibolit train --java_folder=src/java --skip_collect_dataset

How to contribute?

First, you need to install:

Install the following packages if you don't have :

$ apt-get install ruby-dev libz-dev libxml2

Then, you fork the repo and make the changes. Then, you make sure the build is still clean, by running:

$ make

To build white paper:

$ cd wp
$ latexmk -c && latexmk -pdf wp.tex

If everything is fine, submit a pull request.

Using Docker recommendation pipeline

$ docker run --rm -it \
  -v <absolute_path_to_folder_with_classes>:/in \
  -v <absolute_path_to_out_dir>:/out \
  cqfn/aibolit-image

aibolit's People

Contributors

acheshkov avatar angusev avatar aravij avatar cringoleg avatar dz-s avatar evgeniymaslov avatar katgarmash avatar lukyanoffpashok avatar lyriccoder avatar paulodamaso avatar rultor avatar tribals avatar vitaly-protasov avatar yegor256 avatar zuoqin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aibolit's Issues

README is broken

I run:

$ ~/.local/bin/aibolit src/main/java 
usage: aibolit [-h] [--filename FILENAME] [--version]
aibolit: error: unrecognized arguments: src/main/java

multiple_try pattern

Here it is:

class Foo {
  void bar() {
    try {
      // some code
    } catch (IOException ex) {
      // do something
    }
    // some other code
    try {  // here!
      // some code
    } catch (IOException ex) {
      // do something
    }
  }
}

Once we see more than one try in a single method, it's a pattern.

Document what issues this tool can find

As a possible user of this tool, it's not clear from the first sight why I should use this tool and how it can help me. What issues it looks for and what bugs it can prevent?

I'd suggest to document the rules with examples of good and bad code.

Need to calculate readability metrics

The target class of our model is Readability class. It includes the numeric value from 0 up to 1 and tells us how well-readable the code is.

At the moment, we do not have lots of reviewers to review all Java files.
It is necessary to do the script which runs JAR (see the reference below) which estimates Readability. It is the result of the following paper :

https://doi.org/10.1002/smr.1958

The reference of the paper is the following:

TY - JOUR
AU - Scalabrino, Simone
AU - Linares-Vásquez, Mario
AU - Oliveto, Rocco
AU - Poshyvanyk, Denys
C7 - e1958
C8 - smr.1958
TI - A comprehensive model for code readability
JO - Journal of Software: Evolution and Process
JA - J Softw Evol Proc
VL - 30
IS - 6
SN - 2047-7473
UR - https://doi.org/10.1002/smr.1958
DO - doi:10.1002/smr.1958
SP - e1958
KW - code readability
KW - quality warning prediction
KW - textual analysis
PY - 2018
AB - Abstract Unreadable code could compromise program comprehension, and it could cause the introduction of bugs. Code consists of mostly natural language text, both in identifiers and comments, and it is a particular form of text. Nevertheless, the models proposed to estimate code readability take into account only structural aspects and visual nuances of source code, such as line length and alignment of characters. In this paper, we extend our previous work in which we use textual features to improve code readability models. We introduce 2 new textual features, and we reassess the readability prediction power of readability models on more than 600 code snippets manually evaluated, in terms of readability, by 5K+ people. We also replicate a study by Buse and Weimer on the correlation between readability and FindBugs warnings, evaluating different models on 20 software systems, for a total of 3M lines of code. The results demonstrate that (1) textual features complement other features and (2) a model containing all the features achieves a significantly higher accuracy as compared with all the other state-of-the-art models. Also, readability estimation resulting from a more accurate model, ie, the combined model, is able to predict more accurately FindBugs warnings.
ER -

classic_getter pattern

This is the pattern:

class Book {
  private String title;
  void getTitle() {
    return this.title;
  }
}

The method's name starts with get, then goes the name of the attribute. The only statement in the method's body is the return of the attribute.

Check Null: Improvement

We need to check the following cases also for null_check pattern:

  1. boolean i = z == null;
  2. boolean i = z != null;
  3. luckyName != null ? luckyName : "No lucky name found";
  4. if (z != null)
  5. luckyName == null ? luckyName : "No lucky name found";
  6. assert param != null;
  7. assertThrows(NullPointerException.class, () -> wrapperSum(null, 2));
  8. Optional op2 = Optional.ofNullable(null);
  9. if (one == null || two == null || three == null)
  10. Objects.requireNonNull(bar, "bar must not be null");
  11. public void accept(String param){ if (null != param && !param.isEmpty()) System.out.println(param); }

var-in-the-middle doesn't work as expected

Try this Java class:

package org.takes.http;

public final class BkBasic implements Back {
    private static Response failure(final Throwable err, final int code)
        throws IOException {
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (PrintStream stream = new Utf8PrintStream(baos, false)) {
            err.printStackTrace(stream);
        }
        return new RsWithStatus(
            new RsText(new ByteArrayInputStream(baos.toByteArray())),
            code
        );
    }
}

Aibolit says that the variable baos is in the middle of the method, but it's not.

er_class pattern

If a class name is one of the following (or ends with this word), it's the pattern:

Manager, Controller, Router, Dispatcher, Printer, Writer,
Reader, Parser, Generator, Renderer, Listener, Producer,
Holder, Interceptor

Need to write console program

Need to write console program which will find all patterns and show the most important one.
Also, need to make program compilation with all modules embedded

var_decl_diff doesn't work properly with anonymous class, nested class and autocloseable

Example:

  1. autocloseable:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
 
public class TryWithResourcesExample {
    private final static String FILENAME = "file1.txt";
 
    public static void main(String[] args) {
		 new Thread() {

            @Override
            public void run() {
                ArrayList<Boolean> list = new ArrayList<Boolean>();
                for (int i = 0; i < 10; i++)
                    for (int j = 0; j < 10; j++)
                        list.add(Boolean.FALSE);
                super.method1();
            }
        }.start();
        try(BufferedReader rd = new BufferedReader(new FileReader(FILENAME))) {
            String inputLine = null;
            super.method3();
            while((inputLine = rd.readLine()) != null)
                System.out.println(inputLine);
        }
        catch (IOException ex) {
            System.err.println("An IOException was caught: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
}
  1. nested class
import java.util.ArrayList;

class Test {

    class TestInside extends BaseClass {
		
		@Override
        public void start() {
			super(9);
            ArrayList<Boolean> list = new ArrayList<Boolean>();
            for (int i = 0; i < 10; i++)
                for (int i = 0; i < 10; i++)
                    list.add(Boolean.FALSE);
        }
    }

    TestInside a = new TestInside();

    public void start() {
        final JndiService jndiService = serviceRegistry
                .getService(JndiService.class);
        final ConnectionFactory jmsConnectionFactory = jndiService
                .locate(jmsConnectionFactoryName);

        this.jmsConnection = jmsConnectionFactory.createConnection();
        this.jmsSession = jmsConnection.createSession(
                true,
                Session.AUTO_ACKNOWLEDGE
        );
        ArrayList<Boolean> list = new ArrayList<Boolean>();
        for (int i = 0; i < 10; i++)
            list.add(Boolean.FALSE);
        ArrayList<Boolean> list = new ArrayList<Boolean>();
        for (int i = 0; i < 10; i++)
            list.add(Boolean.FALSE);

        this.publisher = jmsSession.createProducer(destination);
    }

    public void foo() {
        a.start();
    }
}
  1. anonymous class
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
 
public class TryWithResourcesExample {
    private final static String FILENAME = "file1.txt";
 
    public static void main(String[] args) {
		 new Thread() {

            @Override
            public void run() {
				super.method1();
                ArrayList<Boolean> list = new ArrayList<Boolean>();
                for (int i = 0; i < 10; i++)
                    for (int j = 0; j < 10; j++)
                        list.add(Boolean.FALSE);
            }
        }.start();
    }
}

redundant_catch pattern

Here it is:

class Book {
  void foo() throws IOException {
    try {
      Files.readAllBytes();
    } catch (IOException e) { // here
      // do something
    }
  }
}

Here, the method foo() throws IOException, but we catch it inside the method.

return_null pattern

Here it is:

class Book {
  String foo() {
    return null;
  }
}

When we return null, it's a pattern.

Pattern: Class implements more than 1 interface

Here:

interface In1 
{ 
    // public, static and final 
    final int a = 10; 
  
    // public and abstract  
    void display(); 
} 

interface In2
{ 
    // public, static and final 
    final int a = 10; 
  
    // public and abstract  
    void cut(); 
} 
  
class Book implements In1, In2 {
  private final int a;
  Book(int x) {
    this.x = a;
  }
  void cut {}
  void display{}
}

Here, we have two interfaces and a class implements more than 1 interface.

Var_middle doesn't work properly with anonymous class, nested class and autocloseable

Example:

  1. autocloseable:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
 
public class TryWithResourcesExample {
    private final static String FILENAME = "file1.txt";
 
    public static void main(String[] args) {
		 new Thread() {

            @Override
            public void run() {
                ArrayList<Boolean> list = new ArrayList<Boolean>();
                for (int i = 0; i < 10; i++)
                    for (int j = 0; j < 10; j++)
                        list.add(Boolean.FALSE);
                super.method1();
            }
        }.start();
        try(BufferedReader rd = new BufferedReader(new FileReader(FILENAME))) {
            String inputLine = null;
            super.method3();
            while((inputLine = rd.readLine()) != null)
                System.out.println(inputLine);
        }
        catch (IOException ex) {
            System.err.println("An IOException was caught: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
}
  1. nested class
import java.util.ArrayList;

class Test {

    class TestInside extends BaseClass {
		
		@Override
        public void start() {
			super(9);
            ArrayList<Boolean> list = new ArrayList<Boolean>();
            for (int i = 0; i < 10; i++)
                for (int i = 0; i < 10; i++)
                    list.add(Boolean.FALSE);
        }
    }

    TestInside a = new TestInside();

    public void start() {
        final JndiService jndiService = serviceRegistry
                .getService(JndiService.class);
        final ConnectionFactory jmsConnectionFactory = jndiService
                .locate(jmsConnectionFactoryName);

        this.jmsConnection = jmsConnectionFactory.createConnection();
        this.jmsSession = jmsConnection.createSession(
                true,
                Session.AUTO_ACKNOWLEDGE
        );
        ArrayList<Boolean> list = new ArrayList<Boolean>();
        for (int i = 0; i < 10; i++)
            list.add(Boolean.FALSE);
        ArrayList<Boolean> list = new ArrayList<Boolean>();
        for (int i = 0; i < 10; i++)
            list.add(Boolean.FALSE);

        this.publisher = jmsSession.createProducer(destination);
    }

    public void foo() {
        a.start();
    }
}
  1. anonymous class
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
 
public class TryWithResourcesExample {
    private final static String FILENAME = "file1.txt";
 
    public static void main(String[] args) {
		 new Thread() {

            @Override
            public void run() {
				super.method1();
                ArrayList<Boolean> list = new ArrayList<Boolean>();
                for (int i = 0; i < 10; i++)
                    for (int j = 0; j < 10; j++)
                        list.add(Boolean.FALSE);
            }
        }.start();
    }
}

pip install does not install dependencies

I instaledl aibolit with

$ pip install --user aibolit
Collecting aibolit
  Downloading https://files.pythonhosted.org/packages/ab/90/0f9885ad2c3fa0e22a173fdbbdf70391caf759fdd1a215b48cc7f1ec04d0/aibolit-0.0.4-py2.py3-none-any.whl
Installing collected packages: aibolit
Successfully installed aibolit-0.0.4

And then I tried to run it:

$ aibolit processor/src/main/java
Traceback (most recent call last):
  File "/home/victor/.local/bin/aibolit", line 5, in <module>
    from aibolit.__main__ import main
  File "/home/victor/.local/lib/python3.8/site-packages/aibolit/__main__.py", line 31, in <module>
    from aibolit.patterns.nested_blocks.nested_blocks import NestedBlocks, BlockType
  File "/home/victor/.local/lib/python3.8/site-packages/aibolit/patterns/nested_blocks/nested_blocks.py", line 23, in <module>
    import javalang
ModuleNotFoundError: No module named 'javalang'

Apparently some dependencies must be missing... the setup.py should be referencing them so that pip install can install them.

assert_in_code pattern

Here it is:

class Book {
  void foo(String x) {
    assert x != null; // here
  } 
}

Once you see the assert statement and class name doesn't end with Test, it's a pattern.

multiple_while pattern

Here it is:

class Book {
  void foo() {
    while (true) {
    }
    // something
    while (true) {
    }
  }
}

Once you see two or more while statements in a method body, it's a pattern.

var_decl_diff_number_5

This code is valid, but the pattern catches it:

class Foo {
  private int x;
  class Foo() {
    this.x = 1;
  }
  void xx() {
    System.out.println("hey");
  }
  void bar() {
    this.x++;
  }
}

Create download java repositories script

Create a script to:

  1. Download trending java repositories first 100
  2. git clone to local
  3. find .java files length > 50 and < 300 lines
  4. output list of paths to such files

classic_setter pattern

This is the pattern:

class Book {
  private String title;
  void setTitle(String) {
    this.title = t;
  }
}

The method's name starts with set, then goes the name of the attribute. The only statement in the method's body is the assignment of the attribute.

Need to filter java files

At the moment we have different files, but we do not need Test files, Enums, AbstractFiles, Interfaces

null_check pattern

This is the pattern:

class Foo {
  private String z;
  void x() {
    if (this.z == null) { // here!
      throw new RuntimeException("oops");
    }
  }
}

The check for null is the pattern.

The pattern should not check constructors.

partial_synchronized pattern

Here it is:

class Book {
  private int a;
  void foo() {
    synchronized (this.a) {
      this.a = 2;
    }
    this.a = 1; // here!
  }
}

Here, the synchronized block doesn't include all statements of the method. Something stays out of the block.

first simple metric-finding object

Let's implement the first simple LocMetric class, which will return the number of lines of code from a java class. Let's place it into aibolit/metrics/loc. Let's make sure we have it covered with unit tests, static analysis, and coverage control.

No License in `aibolit/patterns` folder for many patterns

No License in patterns aibolit/folder for many patterns

# The MIT License (MIT)
#
# Copyright (c) 2020 Aibolit
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

Need to fix them

Need to calculate Halstead Metrics

Often, Halstead metrics are used to measure readability code as it is demonstrated in the following paper:

Daryl Posnett, Abram Hindle, and Premkumar Devanbu. 2011. A simpler model of software readability. In Proceedings of the 8th Working Conference on Mining Software Repositories (MSR ’11). Association for Computing Machinery, New York, NY, USA, 73–82. DOI:https://doi.org/10.1145/1985441.1985454

We need to calculate at least Volume with the following program (or find a similar program):

https://github.com/aametwally/Halstead-Complexity-Measures

empty_rethrow pattern

This is the pattern:

class Book {
  void foo() throws IOException {
    try {
      File.readAllBytes();
    } catch (IOException e) {
      // maybe something else here
      throw e; // here!
    }
  }
}

Here we throw the same exception.

non_final_attribute pattern

Here it is:

class Book {
  private int id;
  // something else
}

Once we see a mutable attribute (without final modifier), it's a pattern

Use assert methods of `unittest.TestCase` class rather than bare `assert` statement in tests

If you're using stdlib's unittest package for writing tests, you shouldn't use "bare" assert statements. They are intended for different purposes - to provide quick-fail validation of function call preconditions. But even this usage is considered an anti-pattern in community.

The issue is that assert statement could be stripped out by interpreter when you turn optimization on, so your tests will never fail. I'll cite docs here for conveniece:

-O
Remove assert statements and any code conditional on the value of __debug__. Augment the filename for compiled (bytecode) files by adding .opt-1 before the .pyc extension (see PEP 488). See also PYTHONOPTIMIZE.

Here is example.

We have simple test:

from unittest import TestCase


class TestTruth(TestCase):
    def test_true_is_false_bare_assert(self):
        assert True is False

    def test_true_is_false_assert_method(self):
        self.assertEqual(True, False)

Let's run it!

$ python3 -m unittest test_truth.py 
FF
======================================================================
FAIL: test_true_is_false_assert_method (test_truth.TestTruth)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tosh/spikes/python-bare-assert/test_truth.py", line 9, in test_true_is_false_assert_method
    self.assertEqual(True, False)
AssertionError: True != False

======================================================================
FAIL: test_true_is_false_bare_assert (test_truth.TestTruth)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tosh/spikes/python-bare-assert/test_truth.py", line 6, in test_true_is_false_bare_assert
    assert True is False
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=2)

As you would expect, they both fails.

But let's turn optimization now (note added -O switch)!

$ python3 -O -m unittest test_truth.py 
F.
======================================================================
FAIL: test_true_is_false_assert_method (test_truth.TestTruth)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tosh/spikes/python-bare-assert/test_truth.py", line 9, in test_true_is_false_assert_method
    self.assertEqual(True, False)
AssertionError: True != False

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

As you'll see, now only one test fails - the one that uses assert method rather than assert statement.

So, if you decided to write tests using stdlib's unittest package, you must use assert methods. Another option will be to switch testing framework. For example, there is pytest framework, which "overloads" assert statement.

Let's run our test with pytest (with optimization turned on):

$ pip3 install pytest
$ python3 -O -m pytest -q test_truth.py
WARNING: assertions not in test modules or plugins will be ignored because assert statements are not executed by the underlying Python interpreter (are you using python -O?)
FF                                                                                         [100%]
============================================ FAILURES ============================================
___________________________ TestTruth.test_true_is_false_assert_method ___________________________

self = <test_truth.TestTruth testMethod=test_true_is_false_assert_method>

    def test_true_is_false_assert_method(self):
>       self.assertEqual(True, False)
E       AssertionError: True != False

test_truth.py:9: AssertionError
____________________________ TestTruth.test_true_is_false_bare_assert ____________________________

self = <test_truth.TestTruth testMethod=test_true_is_false_bare_assert>

    def test_true_is_false_bare_assert(self):
>       assert True is False
E       assert True is False

test_truth.py:6: AssertionError
==================================== short test summary info =====================================
FAILED test_truth.py::TestTruth::test_true_is_false_assert_method - AssertionError: True != False
FAILED test_truth.py::TestTruth::test_true_is_false_bare_assert - assert True is False
2 failed in 0.03s

Note that pytest even warns you about bare assert statements. It is also more relaxed in other handy ways by contrast to unittest and can run unittest-style tests without additional configuration.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.