Skip to content

Commit

Permalink
Merge pull request #192 from green-code-initiative/PR_156_recup
Browse files Browse the repository at this point in the history
[Rule EC203] Detect unoptimized file formats
  • Loading branch information
dedece35 authored May 22, 2023
2 parents 7044340 + d184350 commit c969bcc
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- [#113](https://github.com/green-code-initiative/ecoCode/issues/113) new PYTHON rule : Use unoptimized vector images
- [#127](https://github.com/green-code-initiative/ecoCode/issues/127) Add Python rule EC404: Usage of generator comprehension instead of list comprehension in for loop declaration
- [#192](https://github.com/green-code-initiative/ecoCode/pull/192) Add Python rule EC203: Detect unoptimized file formats

### Changed

Expand Down
1 change: 1 addition & 0 deletions RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ Some are applicable for different technologies.
| EC5 | Usage of preparedStatement instead of Statement | SQL will only commit the query once, whereas if you used only one statement, it would commit the query every time and thus induce unnecessary calculations by the CPU and therefore superfluous energy consumption. | || 🚫 | 🚫 | 🚫 | 🚫 |
| EC27 | Usage of system.arraycopy to copy arrays | Programs spend most of the time in loops. These can be resource consuming, especially when they integrate heavy processing (IO access). Moreover, the size of the data and processing inside the loops will not allow full use of hardware mechanisms such as the cache or compiler optimization mechanisms. | || 🚫 | 🚫 | 🚫 | 🚫 |
| EC404 | Avoid list comprehension in iterations | Use generator comprehension instead of list comprehension in for loop declaration | | 🚫 | 🚫 | 🚫 || 🚫 |
| EC203 | Detect unoptimized file formats | When it is possible, to use svg format image over other image format | | 🚀 | 🚀 | 🚀 || 🚀 |
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,7 @@
import java.util.Collections;
import java.util.List;

import fr.greencodeinitiative.java.checks.ArrayCopyCheck;
import fr.greencodeinitiative.java.checks.AvoidConcatenateStringsInLoop;
import fr.greencodeinitiative.java.checks.AvoidFullSQLRequest;
import fr.greencodeinitiative.java.checks.AvoidGettingSizeCollectionInLoop;
import fr.greencodeinitiative.java.checks.AvoidMultipleIfElseStatement;
import fr.greencodeinitiative.java.checks.AvoidRegexPatternNotStatic;
import fr.greencodeinitiative.java.checks.AvoidSQLRequestInLoop;
import fr.greencodeinitiative.java.checks.AvoidSetConstantInBatchUpdate;
import fr.greencodeinitiative.java.checks.AvoidSpringRepositoryCallInLoopCheck;
import fr.greencodeinitiative.java.checks.AvoidStatementForDMLQueries;
import fr.greencodeinitiative.java.checks.AvoidUsageOfStaticCollections;
import fr.greencodeinitiative.java.checks.AvoidUsingGlobalVariablesCheck;
import fr.greencodeinitiative.java.checks.FreeResourcesOfAutoCloseableInterface;
import fr.greencodeinitiative.java.checks.IncrementCheck;
import fr.greencodeinitiative.java.checks.InitializeBufferWithAppropriateSize;
import fr.greencodeinitiative.java.checks.NoFunctionCallWhenDeclaringForLoop;
import fr.greencodeinitiative.java.checks.OptimizeReadFileExceptions;
import fr.greencodeinitiative.java.checks.UnnecessarilyAssignValuesToVariables;
import fr.greencodeinitiative.java.checks.UseCorrectForLoop;
import fr.greencodeinitiative.java.checks.*;
import org.sonar.plugins.java.api.JavaCheck;

public final class RulesList {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ public List<Class> checkClasses() {
AvoidUnoptimizedVectorImagesCheck.class,
NoFunctionCallWhenDeclaringForLoop.class,
AvoidFullSQLRequest.class,
AvoidListComprehensionInIterations.class
AvoidListComprehensionInIterations.class,
DetectUnoptimizedImageFormat.class
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package fr.greencodeinitiative.python.checks;

import org.sonar.check.Priority;
import org.sonar.check.Rule;
import org.sonar.plugins.python.api.PythonSubscriptionCheck;
import org.sonar.plugins.python.api.SubscriptionContext;
import org.sonar.plugins.python.api.tree.StringLiteral;
import org.sonar.plugins.python.api.tree.Tree;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Rule(
key = DetectUnoptimizedImageFormat.RULE_KEY,
name = DetectUnoptimizedImageFormat.MESSAGERULE,
description = DetectUnoptimizedImageFormat.MESSAGEERROR,
priority = Priority.MINOR,
tags = {"eco-design", "ecocode", "performance", "user-experience"})
public class DetectUnoptimizedImageFormat extends PythonSubscriptionCheck {

protected static final String RULE_KEY = "EC203";
protected static final String MESSAGERULE = "Detect unoptimized image format";
protected static final String MESSAGEERROR = "If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.";
protected static final Pattern IMGEXTENSION = Pattern.compile("\\.(bmp|ico|tiff|webp|png|jpg|jpeg|jfif|pjpeg|pjp|gif|avif|apng)");

@Override
public void initialize(Context context) {
context.registerSyntaxNodeConsumer(Tree.Kind.STRING_LITERAL, this::visitNodeString);
}

public void visitNodeString(SubscriptionContext ctx) {
if (ctx.syntaxNode().is(Tree.Kind.STRING_LITERAL)) {
final StringLiteral stringLiteral = (StringLiteral) ctx.syntaxNode();
final String strValue = stringLiteral.trimmedQuotesValue();
final Matcher matcher = IMGEXTENSION.matcher(strValue);
if(matcher.find()) {
ctx.addIssue(stringLiteral, MESSAGEERROR);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<p>If possible, the utilisation of svg image format (or &lt;svg/&gt; html tag) is recommended over other image format.</p>
<p>Because SVGs are generally smaller than other image format, they’re less taxing on your server despite needing to render on load.</p>
<p>When to use SVG :
<ul>
<li>Your image is used for decorative website graphics, logos, icons, graphs and diagrams, and other simple images.</li>
<li>You image require animation.</li>
<li>You image need to be responsive and scale without lack of quality.</li>
</ul>
</p>
<p>Some advantages of using SVG :
<ul>
<li>SVGs are scalable and will render pixel-perfect at any resolution whereas JPEGs, PNGs and GIFs will not.</li>
<li>SVGs are vector images and therefore are usually much smaller in file-size than bitmap-based images.</li>
<li>SVGs can be embedded into the HTML which means they can be cached, edited directly using CSS and indexed for greater accessibility.</li>
<li>SVGs can be animated directly or by using CSS or JavaScript making it easy for web designers to add interactivity to a site.</li>
</ul>
</p>


<h2>Noncompliant Code Example</h2>
<pre>
...
img_jpg = "image.jpg"
...
</pre>
<h2>Compliant Solution</h2>
<pre>
...
img_svg = "image.svg"
...
</pre>

<h2>Noncompliant Code Example</h2>
<pre>
public void foo() {
...
image_format = testImage("image.jpg")
...
}
</pre>
<h2>Compliant Solution</h2>
<pre>
public void foo() {
...
image_format = testImage("image.svg")
...
}
</pre>

<h2>Noncompliant Code Example</h2>
<pre>
public void foo() {
...
return '&lt;html&gt;&lt;img src="xx/xx/image.bmp"&gt;&lt;/html&gt;'
...
}
</pre>
<h2>Compliant Solution</h2>
<pre>
public void foo() {
...
return '&lt;html&gt;&lt;img src="xx/xx/image.svg"&gt;&lt;/html&gt;'
...
}

public void foo2() {
...
return ('&lt;html&gt;&lt;svg width="100" height="100"&gt;' +
'&lt;circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" /&gt;' +
'&lt;/svg&gt;&lt;/html&gt;')
...
}
</pre>
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public void init() {
public void test() {
assertThat(pythonRuleRepository.repositoryKey()).isEqualTo(PythonRuleRepository.REPOSITORY_KEY);
assertThat(context.repositories()).hasSize(1).extracting("key").containsExactly(pythonRuleRepository.repositoryKey());
assertThat(context.repositories().get(0).rules()).hasSize(8);
assertThat(pythonRuleRepository.checkClasses()).hasSize(8);
assertThat(context.repositories().get(0).rules()).hasSize(9);
assertThat(pythonRuleRepository.checkClasses()).hasSize(9);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fr.greencodeinitiative.python.checks;

import org.junit.Test;
import org.sonar.python.checks.utils.PythonCheckVerifier;

public class DetectUnoptimizedImageFormatTest {

@Test
public void test() {
PythonCheckVerifier.verify("src/test/resources/checks/detectUnoptimizedImageFormat.py", new DetectUnoptimizedImageFormat());
PythonCheckVerifier.verifyNoIssue("src/test/resources/checks/detectUnoptimizedImageFormatCompliant.py", new DetectUnoptimizedImageFormat());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,3 @@ def displayMessage(argument1):
requestCompiliant = ' SeLeCt user FrOm myTable'
displayMessage(requestNonCompiliant)
displayMessage(requestCompiliant)


Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ def is_major(self):
return self.age >= 18

def get_weight(self): # Noncompliant {{Avoid creating getter and setter methods in classes}}
return self.weight
return self.weight
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ def boo():
if os.path.isfile(path):
fh = open(path, 'r')
print(fh.read())
fh.close
fh.close
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

def testImage(image) :
return "path/to/" + image


def testImageFormat2() :

img_bmp = "test/image.bmp" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_ico = "image.ico" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_tiff = "test/path/to/image.tiff" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_webp = "test/path/to/" + "image.webp" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_jpg = "image.jpg" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_jpeg = "image.jpeg" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_jfif = "image.jfif" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_pjpeg = "image.pjpeg" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_pjp = "image.pjp" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_gif = "image.gif" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_avif = "image.avif" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
img_apng = "image.apng" # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}

image_format = testImage("image.jpg") # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}

return ('<html><img src="xx/xx/image.bmp" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.ico" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.tiff" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.webp" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.png" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.jpg" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.jpeg" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.jfif" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.pjpeg" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.pjp" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.gif" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.avif" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '<img src="xx/xx/image.apng" >' # Noncompliant {{If possible, the utilisation of svg image format (or <svg/> html tag) is recommended over other image format.}}
+ '</html>' )
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

def testImage(image) :
return "path/to/" + image


def testImageFormat2() :

img_svg = "test/image.svg" # Compliant

image_format = testImage("image.svg") # Compliant

image_svg_html = ('<html><svg width="100" height="100">' + # Compliant
'<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />' +
'</svg></html>')

return ('<html><img src="xx/xx/image.svg" >' # Compliant
+ '</html>' )
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@ def my_function():
my_function()
pass



my_function()
my_function()

0 comments on commit c969bcc

Please sign in to comment.