getSharedLibraryPaths() throws IOException {
29 | NativeCodeManifest manifest = NativeCodeManifest.fromJarFile(this.jarFile);
30 |
31 | // No native code manifest found
32 | if (manifest == null) return List.of();
33 |
34 | return manifest.getRecords().stream()
35 | .filter(NativeCodeManifestRecord::isAarch64)
36 | .filter(NativeCodeManifestRecord::isLinux)
37 | .map(NativeCodeManifestRecord::getLibpath)
38 | .collect(Collectors.toList());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/advisor/tools/ampere-ready-java/src/main/java/com/ampere/labs/GravitonReadyAssessor/NativeCodeManifest.java:
--------------------------------------------------------------------------------
1 | package com.ampere.labs.AmpereReadyAssessor;
2 |
3 | import lombok.Getter;
4 | import lombok.NonNull;
5 |
6 | import java.io.IOException;
7 | import java.util.Arrays;
8 | import java.util.jar.Attributes;
9 | import java.util.jar.JarFile;
10 | import java.util.jar.Manifest;
11 | import java.util.List;
12 | import java.util.stream.Collectors;
13 |
14 | /**
15 | * A native code bundle JAR manifest entry.
16 | *
17 | * JAR files have
18 | * manifests
19 | * in them which contain various metadata in them. These metadata are known as
20 | * attributes. Some
21 | * JAR files have a Bundle-NativeCode
attribute in them that indicates where native code
22 | * can be found. The format of this attribute's value is defined by the OSGI Framework and is
23 | * documented here.
24 | */
25 | public class NativeCodeManifest {
26 | final static String BundleNativeCode = "Bundle-NativeCode";
27 |
28 | @Getter
29 | private List records;
30 |
31 | /**
32 | * Constructs a NativeCodeManifest from a JarFile object.
33 | * @param jarFile the JarFile
34 | * @return the NativeCodeManifest
35 | * @throws IOException
36 | */
37 | public static NativeCodeManifest fromJarFile(@NonNull JarFile jarFile) throws IOException {
38 | Manifest manifest = jarFile.getManifest();
39 | Attributes attrs = manifest.getMainAttributes();
40 | String bundleNativeCode = attrs.getValue(BundleNativeCode);
41 |
42 | if (bundleNativeCode == null) return null;
43 |
44 | return fromString(bundleNativeCode);
45 | }
46 |
47 | /**
48 | * Constructs a NativeCodeManifest from a JarFile object.
49 | * @param attributeValue the value of the Bundle-NativeCode Manifest attribute
50 | * @return the NativeCodeManifest
51 | */
52 | private static NativeCodeManifest fromString(@NonNull String attributeValue) {
53 | NativeCodeManifest manifest = new NativeCodeManifest();
54 |
55 | // Records are separated by `,`
56 | manifest.records = Arrays.stream(attributeValue.split(","))
57 | .map(String::trim)
58 | .map(NativeCodeManifestRecord::fromString)
59 | .collect(Collectors.toUnmodifiableList());
60 | return manifest;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/advisor/tools/ampere-ready-java/src/main/java/com/ampere/labs/GravitonReadyAssessor/NativeCodeManifestRecord.java:
--------------------------------------------------------------------------------
1 | package com.ampere.labs.AmpereReadyAssessor;
2 |
3 | import lombok.Getter;
4 | import lombok.NonNull;
5 | import lombok.Setter;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * A record in a Bundle-NativeCode JAR manifest attribute.
12 | */
13 | public class NativeCodeManifestRecord {
14 | @Getter
15 | @Setter
16 | private String libpath;
17 |
18 | private final List osnames = new ArrayList<>();
19 | private final List arches = new ArrayList<>();
20 |
21 | /**
22 | * Creates a NativeCodeManifestRecord from its string representation.
23 | * @param text The raw text
24 | * @return a NativeCodeManifestRecord
25 | */
26 | public static NativeCodeManifestRecord fromString(@NonNull String text) {
27 | NativeCodeManifestRecord entry = new NativeCodeManifestRecord();
28 | List kvPairs = List.of(text.split(";"));
29 | entry.setLibpath(kvPairs.get(0));
30 | // Record any processor architectures or OS names found within
31 | kvPairs.stream().skip(1).forEach(pair -> {
32 | String key = pair.split("=")[0];
33 | String val = pair.split("=")[1];
34 | if (key.equals("osname")) {
35 | entry.addOSName(val);
36 | }
37 | if (key.equals("processor")) {
38 | entry.addArch(val);
39 | }
40 | });
41 | return entry;
42 | }
43 |
44 | public void addOSName(String osName) {
45 | osnames.add(osName);
46 | }
47 |
48 | public void addArch(String arch) {
49 | arches.add(arch);
50 | }
51 |
52 | public boolean isLinux() {
53 | return osnames.stream().anyMatch(name -> name.equalsIgnoreCase("linux"));
54 | }
55 |
56 | public boolean isAarch64() {
57 | return arches.stream().anyMatch(name -> name.equalsIgnoreCase("aarch64"));
58 | }
59 |
60 | @Override
61 | public String toString() {
62 | return "libpath: " + libpath + "; arches=" + this.arches + "; osnames=" + this.osnames;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/advisor/tools/ampere-ready-java/src/main/java/com/ampere/labs/GravitonReadyAssessor/SimpleLogger.java:
--------------------------------------------------------------------------------
1 | package com.ampere.labs.AmpereReadyAssessor;
2 |
3 | import lombok.NonNull;
4 |
5 | import java.io.OutputStream;
6 | import java.util.Properties;
7 | import java.util.logging.*;
8 |
9 | /**
10 | * A simple unbuffered logger that simply prints each log line as-is to standard output (System.out).
11 | */
12 | public class SimpleLogger {
13 | private static Logger logger;
14 | private static Handler handler;
15 |
16 | static {
17 | Properties logProps = System.getProperties();
18 | logProps.setProperty("java.util.logging.SimpleFormatter.format", "%5$s%n");
19 | System.setProperties(logProps);
20 | }
21 |
22 | /**
23 | * Obtain the singleton Logger instance.
24 | *
25 | * @return The logger instance
26 | * @throws SecurityException
27 | */
28 | public static Logger getLogger() throws SecurityException {
29 | if (logger != null) {
30 | return logger;
31 | }
32 | logger = Logger.getLogger(SimpleLogger.class.toString());
33 | logger.setUseParentHandlers(false);
34 | handler = getAutoFlushingStreamHandler(System.out, new SimpleFormatter());
35 | logger.addHandler(handler);
36 | return logger;
37 | }
38 |
39 | /**
40 | * Sets the lowest log level that this logger will emit. Logs with a level lower than
41 | * this will be omitted from the output.
42 | *
43 | * @param level The log level
44 | */
45 | public static void setLevel(@NonNull Level level) {
46 | if (logger == null) getLogger();
47 | handler.setLevel(level);
48 | logger.setLevel(level);
49 | }
50 |
51 | /**
52 | * Returns a StreamHandler that flushes after every publish() invocation.
53 | * @param o the OutputStream passed to the StreamHandler constructor
54 | * @param f the Formatter passed to the StreamHandler constructor
55 | * @return
56 | */
57 | private static StreamHandler getAutoFlushingStreamHandler(@NonNull OutputStream o, @NonNull Formatter f) {
58 | return new StreamHandler(o, f) {
59 | @Override
60 | public synchronized void publish(@NonNull final LogRecord record) {
61 | super.publish(record);
62 | flush();
63 | }
64 | };
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/advisor/tools/ampere-ready-java/src/test/files/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "classes" : [ {
3 | "implementationTitle" : "ImplementationTitle",
4 | "implementationVendor" : "ImplementationVendor",
5 | "implementationVersionRange" : "[1.0.0,2.0.0)",
6 | "specificationTitle" : "SpecificationTitle",
7 | "specificationVendor" : "SpecificationVendor",
8 | "specificationVersionRange" : "[1.0.0,2.0.0)",
9 | "status" : "OK",
10 | "description" : "Description goes here",
11 | "url" : "http://example.com",
12 | "lastUpdated" : "2022-01-22T00:50:03.114+00:00"
13 | } ]
14 | }
--------------------------------------------------------------------------------
/src/advisor/tools/ampere-ready-java/src/test/java/com/ampere/labs/GravitonReadyAssessor/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.ampere.labs.AmpereReadyAssessor;
2 |
3 | import static org.junit.Assert.assertTrue;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | {
12 | /**
13 | * Rigorous Test :-)
14 | */
15 | @Test
16 | public void shouldAnswerWithTrue()
17 | {
18 | assertTrue( true );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/advisor/tools/ampere-ready-java/src/test/java/com/ampere/labs/GravitonReadyAssessor/ConfigFileTest.java:
--------------------------------------------------------------------------------
1 | package com.ampere.labs.AmpereReadyAssessor;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 |
5 | import org.junit.Test;
6 |
7 | import static org.junit.Assert.*;
8 |
9 | import org.osgi.framework.Version;
10 | import org.osgi.framework.VersionRange;
11 |
12 | import java.io.IOException;
13 | import java.net.MalformedURLException;
14 | import java.net.URL;
15 | import java.util.Date;
16 |
17 | public class ConfigFileTest {
18 | @Test
19 | public void shouldLoadConfigFile() {
20 | try {
21 | URL url = new URL("file:src/test/files/config.json");
22 | Config c = Config.fromURL(url);
23 | System.out.println(c);
24 | } catch (IOException e) {
25 | fail(e.toString());
26 | }
27 | }
28 |
29 | @Test
30 | public void shouldPrintJSON() {
31 | try {
32 | Config c = generateConfig();
33 | System.out.println(c.toJson());
34 | } catch(JsonProcessingException e) {
35 | fail(e.toString());
36 | }
37 | }
38 |
39 | @Test
40 | public void shouldSerializeDeserialize() {
41 | try {
42 | Config c1 = generateConfig();
43 | String json = c1.toJson();
44 | Config c2 = Config.fromJson(json);
45 | assertEquals(c1, c2);
46 | } catch(JsonProcessingException e) {
47 | fail(e.toString());
48 | }
49 | }
50 |
51 | @Test
52 | public void versionInRange() {
53 | Config config = generateConfig();
54 | assert(config.getClassInfos().size() == 1);
55 | ClassInfo info = config.getClassInfos().get(0);
56 | // TODO
57 | return;
58 | }
59 |
60 | private Config generateConfig() {
61 | try {
62 | ClassInfo i = ClassInfo.builder()
63 | .implementationTitle("ImplementationTitle")
64 | .implementationVendor("ImplementationVendor")
65 | .implementationVersionRange(
66 | new VersionRange(
67 | VersionRange.LEFT_CLOSED, new Version(1, 0, 0),
68 | new Version(2, 0, 0), VersionRange.RIGHT_OPEN)
69 | )
70 | .specificationTitle("SpecificationTitle")
71 | .specificationVendor("SpecificationVendor")
72 | .specificationVersionRange(
73 | new VersionRange(
74 | VersionRange.LEFT_CLOSED, new Version(1, 0, 0),
75 | new Version(2, 0, 0), VersionRange.RIGHT_OPEN)
76 | )
77 | .description("Description goes here")
78 | .status("OK")
79 | .url(new URL("http://example.com"))
80 | .lastUpdated(new Date())
81 | .build();
82 | return Config.builder()
83 | .classInfo(i)
84 | .build();
85 | } catch (MalformedURLException e) {
86 | fail(e.toString());
87 | return null;
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/advisor/tools/ampere-ready-java/target/placeholder.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmpereComputing/ampere-porting-advisor/510aa1345d4ac2c61e9fc3b0ab145a1ba5178dd6/src/advisor/tools/ampere-ready-java/target/placeholder.md
--------------------------------------------------------------------------------
/src/porting-advisor.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | """
3 | Copyright 2017 Arm Ltd.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 |
17 | SPDX-License-Identifier: Apache-2.0
18 | """
19 | import sys
20 |
21 | from advisor import main
22 |
23 | if __name__ == '__main__':
24 | if sys.version_info < (3, 10):
25 | print("Python 3.10 or newer is required to run this application.")
26 | sys.exit(1)
27 | main()
28 |
--------------------------------------------------------------------------------
/src/updater.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | import sys
4 | from advisor import __version__
5 | from advisor.helpers.version_comparer import VersionComparer
6 | from zipfile import ZipFile
7 |
8 | # Temp test bucket
9 | DOWNLOAD_URL = ''
10 | LATEST_VERSION_URL = ''
11 |
12 | def main(argv=sys.argv[1:]):
13 | check_for_updates()
14 |
15 |
16 | def check_for_updates():
17 | """Checks for latest version. Displays a message if new message is available.
18 | """
19 | if (is_newer_version_available()):
20 | print(f'New version of Porting Advisor for Ampere is available. Please download it at: {DOWNLOAD_URL}')
21 |
22 | def is_newer_version_available():
23 | current_version = __version__
24 | latest_version = get_latest_version()
25 | return VersionComparer.is_valid(latest_version) and VersionComparer.compare(current_version, latest_version) == -1
26 |
27 | def get_latest_version():
28 | """Gets latest version available
29 |
30 | Returns:
31 | str: The latest published version. Empty if it failed to get the latest version available.
32 | """
33 | try:
34 | return do_request(LATEST_VERSION_URL).decode('utf-8')
35 | except:
36 | logging.debug('Error while getting latest version.', exc_info=True)
37 | return ''
38 |
39 | def do_request(request_url):
40 | """Executes an https request
41 | Returns:
42 | bytes: The latest version of the tool. None if it fails.
43 | """
44 | try:
45 | # if running as a binary, need to specify the path to the cacert.pem for requests to succeed
46 | if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
47 | import certifi.core
48 | certifi.core.where = _get_cacert_pem()
49 | import requests.utils
50 | import requests.adapters
51 | requests.utils.DEFAULT_CA_BUNDLE_PATH = _get_cacert_pem()
52 | requests.adapters.DEFAULT_CA_BUNDLE_PATH = _get_cacert_pem()
53 | else:
54 | import certifi.core
55 | import requests.utils
56 | import requests.adapters
57 |
58 | return requests.get(request_url).content
59 | except:
60 | logging.debug('Error while executing https request.', exc_info=True)
61 | return None
62 |
63 | def _get_cacert_pem():
64 | return os.path.abspath(os.path.join(os.path.dirname(__file__), 'certifi', 'cacert.pem'))
65 |
66 | if __name__ == '__main__':
67 | main()
68 |
--------------------------------------------------------------------------------
/test-helpers.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function test_line() {
4 | reportType=$1
5 | result_filename=$2
6 | pattern=$3
7 | if grep --quiet "$3" "$result_filename"
8 | then
9 | echo "**PASS** $reportType report has: $pattern"
10 | else
11 | echo "**FAILED** $reportType report is missing: $pattern" && exit 1
12 | fi
13 | }
14 |
15 | function test_report() {
16 | report_type=$1
17 | shift
18 | result_filename=$1
19 | shift
20 | patterns=("$@")
21 | for line in "${patterns[@]}";
22 | do
23 | test_line $report_type $result_filename "${line[@]}"
24 | done
25 | }
26 |
27 | declare -a lines_to_find=("detected java code. we recommend using OpenJDK"
28 | "detected python code. min version 3.7.5 is required"
29 | "detected python code. if you need pip, version 19.3 or above is recommended"
30 | "dependency library numpy is present. min version 1.19.0 is required"
31 | "detected java code. min version 8 is required. version 17 or above is recommended"
32 | "using dependency library snappy-java version 1.1.3. upgrade to at least version 1.1.4"
33 | "using dependency library hadoop-lzo. this library requires a manual build"
34 | "dependency library: leveldbjni-all is not supported on Ampere Processors"
35 | "detected go code. min version 1.16 is required. version 1.18 or above is recommended"
36 | "using dependency library github.com/golang/snappy version 0.0.1. upgrade to at least version 0.0.2"
37 | )
38 |
--------------------------------------------------------------------------------
/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Runs unit tests, generates the binary and then runs it against sample projects
4 |
5 | # run unit tests
6 | echo "🐍 Setup virtual environment"
7 | ./setup-environment.sh
8 | if [ $? -ne 0 ]; then
9 | echo "**ERROR**: failed to initialize Python Virtual Environment" && exit 1
10 | fi
11 |
12 | # run unit tests
13 | echo "🔬 Running unit tests"
14 | ./unit-test.sh
15 | if [ $? -ne 0 ]; then
16 | echo "**ERROR**: unit tests failed" && exit 1
17 | fi
18 |
19 | # build project
20 | echo "⚒️ Building project"
21 | ./build.sh
22 | if [ $? -ne 0 ]; then
23 | echo "**ERROR**: failed to build project" && exit 1
24 | fi
25 |
26 | echo "🧪 Running integration tests"
27 | ./integration-test.sh
28 | if [ $? -ne 0 ]; then
29 | echo "**ERROR**: integration tests failed" && exit 1
30 | fi
31 |
32 | # run load tests
33 | echo "⏳ Running load tests"
34 | ./load_test.sh
35 | if [ $? -ne 0 ]; then
36 | echo "**ERROR**: load tests failed" && exit 1
37 | fi
38 |
39 | if hash docker
40 | then
41 | echo "🐋 Running container tests"
42 | ./container-test.sh
43 | if [ $? -ne 0 ]; then
44 | echo "**ERROR**: error generating jar for Ampere Ready Java tool" && exit 1
45 | fi
46 | fi
47 |
--------------------------------------------------------------------------------
/tests-baseline/directory_not_found_test.txt:
--------------------------------------------------------------------------------
1 | unexisting_directory: directory not found.
2 |
--------------------------------------------------------------------------------
/tests-baseline/missing_arguments_test.txt:
--------------------------------------------------------------------------------
1 | usage: porting-advisor [-h] [--issue-types ISSUE_TYPES] [--no-filter]
2 | [--no-progress] [--output OUTPUT]
3 | [--output-format OUTPUT_FORMAT] [--quiet]
4 | [--target-os TARGET_OS] [--version]
5 | [--logging-level {error,warning,info,debug}]
6 | [--log-file LOG_FILE] [--log-to-console]
7 | DIRECTORY
8 | porting-advisor: error: the following arguments are required: DIRECTORY
9 |
--------------------------------------------------------------------------------
/tests-baseline/sample_applications_test.json:
--------------------------------------------------------------------------------
1 | {
2 | "python": {
3 | "type": "git",
4 | "app": "pytorch",
5 | "url": "https://github.com/pytorch/pytorch.git",
6 | "branch": "v2.0.1",
7 | "integrity": {
8 | "architecture-specific AVX-256 intrinsic": 340,
9 | "architecture-specific inline assembly": 45,
10 | "architecture-specific intrinsic": 256
11 | },
12 | "prompts": [
13 | "files scanned",
14 | "150 source files are already ported to aarch64",
15 | "46 inline assembly statements or intrinsics already have aarch64 equivalents",
16 | "detected java code. we recommend using OpenJDK version 17 or above release for aarch64.",
17 | "detected python code. if you need pip, version 19.3 or above is recommended.",
18 | "detected python code. min version 3.7.5 is required.",
19 | "detected java code. min version 8 is required. version 17 or above is recommended",
20 | "dependency library numpy",
21 | "dependency library pyyaml",
22 | "dependency library lxml"
23 | ]
24 | },
25 | "c_cpp": {
26 | "type": "git",
27 | "app": "mysql-server",
28 | "url": "https://github.com/mysql/mysql-server.git",
29 | "branch": "mysql-8.0.33",
30 | "integrity": {
31 | "preprocessor error on aarch64": 2,
32 | "architecture-specific inline assembly": 35,
33 | "architecture-specific intrinsic": 33
34 | },
35 | "prompts": [
36 | "files scanned",
37 | "8 inline assembly statements or intrinsics already have aarch64 equivalents",
38 | "detected java code. we recommend using OpenJDK version 17 or above release for aarch64.",
39 | "detected python code. if you need pip, version 19.3 or above is recommended.",
40 | "detected python code. min version 3.7.5 is required.",
41 | "detected java code. min version 8 is required. version 17 or above is recommended.",
42 | "autoconf config.guess recognizes aarch64 architecture"
43 | ]
44 | },
45 | "java": {
46 | "type": "wget",
47 | "app": "spark-2.3.0-bin-hadoop2.7",
48 | "url": "https://archive.apache.org/dist/spark/spark-2.3.0/spark-2.3.0-bin-hadoop2.7.tgz",
49 | "integrity": {
50 | "JAR has native methods but no libraries found for aarch64/Linux": 10
51 | },
52 | "prompts": [
53 | "files scanned",
54 | "detected java code. we recommend using OpenJDK version 17 or above release for aarch64.",
55 | "detected python code. if you need pip, version 19.3 or above is recommended.",
56 | "detected python code. min version 3.7.5 is required.",
57 | "detected java code. min version 8 is required. version 17 or above is recommended."
58 | ]
59 | },
60 | "go": {
61 | "type": "git",
62 | "app": "cilium",
63 | "url": "https://github.com/cilium/cilium.git",
64 | "branch": "v1.13.2",
65 | "integrity": {
66 | "architecture-specific intrinsic": 1,
67 | "architecture-specific inline assembly": 10,
68 | "architecture-specific assembly source file": 4
69 | },
70 | "prompts": [
71 | "files scanned",
72 | "detected python code. if you need pip, version 19.3 or above is recommended.",
73 | "detected python code. min version 3.7.5 is required.",
74 | "detected go code. min version 1.16 is required. version 1.18 or above is recommended."
75 | ]
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/unit-test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "🐍 Making sure Python Virtual Environment is active"
4 | . .venv/bin/activate
5 | if [ $? -ne 0 ]; then
6 | echo "**ERROR**: could not activate Python Virtual Environment." && exit 1
7 | fi
8 |
9 | # run unit tests
10 | echo "🔬 *** running unit tests ***"
11 | python -m coverage run --source=./src -m unittest discover -s unittest -p "test_*.py" -v
12 | if [ $? -ne 0 ]; then
13 | echo "**ERROR**: unit tests failed" && exit 1
14 | fi
--------------------------------------------------------------------------------
/unittest/test_asm_source_scanner.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2017 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import io
20 | import unittest
21 | from src.advisor.reports.report import Report
22 | from src.advisor.scanners.asm_source_scanner import AsmSourceScanner
23 |
24 |
25 | class TestAsmSourceScanner(unittest.TestCase):
26 | def test_accepts_file(self):
27 | asm_source_scanner = AsmSourceScanner()
28 | self.assertFalse(asm_source_scanner.accepts_file('test.c'))
29 | self.assertFalse(asm_source_scanner.accepts_file('tests'))
30 | self.assertTrue(asm_source_scanner.accepts_file('test.s'))
31 | self.assertTrue(asm_source_scanner.accepts_file('test.S'))
32 |
33 | def test_scan_file_object(self):
34 | asm_source_scanner = AsmSourceScanner()
35 | report = Report('/root')
36 | io_object = io.StringIO('__asm__("")')
37 | asm_source_scanner.scan_file_object('test.s', io_object, report)
38 | self.assertEqual(len(report.issues), 0)
39 | report = Report('/root')
40 | io_object = io.StringIO('__asm__("mov r0, r1")')
41 | asm_source_scanner.scan_file_object('test.s', io_object, report)
42 | self.assertEqual(len(report.issues), 1)
43 |
--------------------------------------------------------------------------------
/unittest/test_config_guess_scanner.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2017 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import io
20 | import unittest
21 | from src.advisor.reports.report import Report
22 | from src.advisor.scanners.config_guess_scanner import ConfigGuessScanner
23 |
24 |
25 | class TestConfigGuessScanner(unittest.TestCase):
26 | def test_accepts_file(self):
27 | config_guess_scanner = ConfigGuessScanner()
28 | self.assertFalse(config_guess_scanner.accepts_file('test'))
29 | self.assertTrue(config_guess_scanner.accepts_file('config.guess'))
30 |
31 | def test_scan_file_object(self):
32 | config_guess_scanner = ConfigGuessScanner()
33 | report = Report('/root')
34 | io_object = io.StringIO('xxx')
35 | config_guess_scanner.scan_file_object(
36 | 'config.guess', io_object, report)
37 | self.assertEqual(len(report.issues), 1)
38 | report = Report('/root')
39 | io_object = io.StringIO('aarch64:Linux')
40 | config_guess_scanner.scan_file_object(
41 | 'config.guess', io_object, report)
42 | self.assertEqual(len(report.remarks), 1)
43 |
--------------------------------------------------------------------------------
/unittest/test_continuation_parser.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import unittest
20 | from src.advisor.parsers.continuation_parser import ContinuationParser
21 |
22 |
23 | class TestOsFilter(unittest.TestCase):
24 | def test_parse_line(self):
25 | continuation_parser = ContinuationParser()
26 | line = continuation_parser.parse_line('just a line')
27 | self.assertEqual(line, 'just a line')
28 | line = continuation_parser.parse_line('')
29 | self.assertEqual(line, '')
30 | line = continuation_parser.parse_line('#define MACRO \\')
31 | self.assertIsNone(line)
32 | line = continuation_parser.parse_line('first line of macro \\')
33 | self.assertIsNone(line)
34 | line = continuation_parser.parse_line('second line of macro')
35 | self.assertEqual(line, '#define MACRO first line of macro second line of macro')
36 |
--------------------------------------------------------------------------------
/unittest/test_csv_report.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2017 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import csv
20 | import io
21 | import tempfile
22 | import unittest
23 | from src.advisor.reports.csv_report import CsvReport
24 | from src.advisor.scanners.config_guess_scanner import ConfigGuessScanner
25 | from src.advisor.scanners.source_scanner import SourceScanner
26 |
27 |
28 | class TestCsvReport(unittest.TestCase):
29 | def test_output(self):
30 | config_guess_scanner = ConfigGuessScanner()
31 | source_scanner = SourceScanner()
32 |
33 | report = CsvReport('/root')
34 | report.add_source_file('test_negative.c')
35 | io_object = io.StringIO('__asm__("mov r0, r1")')
36 | source_scanner.scan_file_object(
37 | 'test_negative.c', io_object, report)
38 | report.add_source_file('test_neutral.c')
39 | io_object = io.StringIO('#pragma simd foo')
40 | source_scanner.scan_file_object(
41 | 'test_neutral.c', io_object, report)
42 | report.add_source_file('config.guess')
43 | io_object = io.StringIO('aarch64:Linux')
44 | config_guess_scanner.scan_file_object(
45 | 'config.guess', io_object, report)
46 | self.assertEqual(len(report.issues), 2)
47 | self.assertEqual(len(report.remarks), 1)
48 |
49 | with tempfile.NamedTemporaryFile(mode='w', delete=False) as ofp:
50 | report.write(ofp)
51 | fname = ofp.name
52 | ofp.close()
53 |
54 | with open(fname) as ifp:
55 | csv_reader = csv.DictReader(ifp)
56 | seen_issue1 = False
57 | seen_issue2 = False
58 | for row in csv_reader:
59 | if 'test_negative.c' in row['filename']:
60 | self.assertIn('InlineAsm', row['issue_type'])
61 | seen_issue1 = True
62 | elif 'test_neutral.c' in row['filename']:
63 | self.assertIn('PragmaSimd', row['issue_type'])
64 | seen_issue2 = True
65 | else:
66 | self.fail('Unexpected row in CSV output')
67 | self.assertTrue(seen_issue1)
68 | self.assertTrue(seen_issue2)
69 |
--------------------------------------------------------------------------------
/unittest/test_find_port.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2017 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import os
20 | import unittest
21 | from src.advisor.helpers.find_port import *
22 |
23 |
24 | class TestFindPort(unittest.TestCase):
25 | def test_port_filenames(self):
26 | self.assertListEqual(port_filenames("filename"), [])
27 | self.assertListEqual(port_filenames("otherarch"),
28 | ['arm', 'aarch64', 'arm64', 'neon', 'sve'])
29 | self.assertListEqual(port_filenames("source-otherarch.c"),
30 | ['source-arm.c', 'source-aarch64.c',
31 | 'source-arm64.c', 'source-neon.c',
32 | 'source-sve.c'])
33 |
34 | def test_find_port_dir(self):
35 | self.assertEqual(find_port_dir('/foo/otherarch',
36 | ['/foo/otherarch', '/foo/aarch64']),
37 | '/foo/aarch64')
38 |
39 | @unittest.skipIf(os.name == 'nt', 'Test fails in Windows')
40 | def test_find_port_file(self):
41 | self.assertEqual(find_port_file('/foo/source-otherarch.c',
42 | ['/foo/source-otherarch.c',
43 | '/foo/source-aarch64.c']),
44 | '/foo/source-aarch64.c')
45 | self.assertEqual(find_port_file('/foo/otherarch/source.c',
46 | ['/foo/otherarch/source.c',
47 | '/foo/aarch64/source.c']),
48 | '/foo/aarch64/source.c')
49 |
50 | @unittest.skipUnless(os.name == 'nt', 'test_find_port_file for Windows only')
51 | def test_find_port_file_windows(self):
52 | self.assertEqual(find_port_file('\\foo\\source-otherarch.c',
53 | ['\\foo\\source-otherarch.c',
54 | '\\foo\\source-aarch64.c']),
55 | '\\foo\\source-aarch64.c')
56 | self.assertEqual(find_port_file('\\foo\\otherarch\\source.c',
57 | ['\\foo\\otherarch\\source.c',
58 | '\\foo\\aarch64\\source.c']),
59 | '\\foo\\aarch64\\source.c')
--------------------------------------------------------------------------------
/unittest/test_issue_type_filter.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018,2020 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import unittest
20 | from src.advisor.filters.issue_type_filter import IssueTypeFilter
21 | from src.advisor.reports.issues.inline_asm_issue import InlineAsmIssue
22 | from src.advisor.reports.issues.issue_type_config import IssueTypeConfig
23 | from src.advisor.reports.report import Report
24 |
25 |
26 | class TestIssueTypeFilter(unittest.TestCase):
27 | def test_finalize(self):
28 | report = Report('/root')
29 | issue_type_config = IssueTypeConfig(None)
30 | issue_type_filter = IssueTypeFilter(issue_type_config)
31 | issue_type_filter.initialize_report(report)
32 | report.add_source_file('test.c')
33 | report.add_issue(InlineAsmIssue('test.c', 123))
34 | issue_type_filter.finalize_report(report)
35 | self.assertEqual(len(report.issues), 1)
36 |
37 | report = Report('/root')
38 | issue_type_config = IssueTypeConfig('-InlineAsm')
39 | issue_type_filter = IssueTypeFilter(issue_type_config)
40 | issue_type_filter.initialize_report(report)
41 | report.add_source_file('test.c')
42 | report.add_issue(InlineAsmIssue('test.c', 123))
43 | issue_type_filter.finalize_report(report)
44 | self.assertEqual(len(report.issues), 0)
45 |
46 | report = Report('/root')
47 | issue_type_config = IssueTypeConfig('InlineAsm')
48 | issue_type_filter = IssueTypeFilter(issue_type_config)
49 | issue_type_filter.initialize_report(report)
50 | report.add_source_file('test.c')
51 | report.add_issue(InlineAsmIssue('test.c', 123))
52 | issue_type_filter.finalize_report(report)
53 | self.assertEqual(len(report.issues), 1)
54 |
55 | report = Report('/root')
56 | issue_type_config = IssueTypeConfig('PreprocessorError')
57 | issue_type_filter = IssueTypeFilter(issue_type_config)
58 | issue_type_filter.initialize_report(report)
59 | report.add_source_file('test.c')
60 | report.add_issue(InlineAsmIssue('test.c', 123))
61 | issue_type_filter.finalize_report(report)
62 | self.assertEqual(len(report.issues), 0)
63 |
--------------------------------------------------------------------------------
/unittest/test_item_type.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2020 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import unittest
20 | from src.advisor.reports.issues.compiler_specific_issue import CompilerSpecificIssue
21 | from src.advisor.reports.report_item import ReportItem
22 |
23 |
24 | class TestItemType(unittest.TestCase):
25 | def test_compiler_specific_issue(self):
26 | issue = CompilerSpecificIssue('filename', 123, 'compiler', 'function')
27 | self.assertEqual(issue.item_type, ReportItem.NEUTRAL)
28 |
--------------------------------------------------------------------------------
/unittest/test_java_tool_invoker.py:
--------------------------------------------------------------------------------
1 | import os
2 | import unittest
3 | import urllib.request
4 | from src.advisor.helpers.java.java_tool_invoker import JavaToolInvoker
5 |
6 |
7 | class TestJavaToolIncoker(unittest.TestCase):
8 | def setUp(self) -> None:
9 | self.tool_invoker = JavaToolInvoker()
10 |
11 | def test_can_run_checks_java_is_installed(self):
12 | self.assertTrue(self.tool_invoker.can_run())
13 |
14 | def test_ampere_ready_assessor_for_jars_with_native_methods(self):
15 | download_url = 'https://repo.maven.apache.org/maven2/io/netty/netty-transport-native-unix-common/4.1.73.Final/netty-transport-native-unix-common-4.1.73.Final.jar'
16 | path = os.path.join('sample-projects', 'java-samples', 'netty-transport-native-unix-common-4.1.73.Final.jar')
17 | urllib.request.urlretrieve(download_url, path)
18 | result, message = self.tool_invoker.ampere_ready_assessor(path)
19 | os.remove(path)
20 | self.assertEqual(3, result)
21 | self.assertTrue(message.startswith('Native methods:'))
22 |
23 | def test_ampere_ready_assessor_for_jars_with_non_native_methods(self):
24 | download_url = 'https://repo.maven.apache.org/maven2/javax/activation/activation/1.1.1/activation-1.1.1.jar'
25 | path = os.path.join('sample-projects', 'java-samples', 'activation-1.1.1.jar')
26 | urllib.request.urlretrieve(download_url, path)
27 | result, message = self.tool_invoker.ampere_ready_assessor(path)
28 | os.remove(path)
29 | self.assertEqual(0, result)
30 | self.assertEqual('No native methods found in scanned JAR files.', message)
31 |
--------------------------------------------------------------------------------
/unittest/test_meson_scanner.py:
--------------------------------------------------------------------------------
1 | """
2 | SPDX-License-Identifier: Apache-2.0
3 | Copyright (c) 2024, Ampere Computing LLC
4 | """
5 |
6 | import io
7 | import unittest
8 | from src.advisor.reports.report import Report
9 | from src.advisor.scanners.meson_scanner import MesonScanner
10 |
11 |
12 | class TestMesonScanner(unittest.TestCase):
13 | def test_accepts_file(self):
14 | meson_scanner = MesonScanner()
15 | self.assertFalse(meson_scanner.accepts_file('test'))
16 | self.assertTrue(meson_scanner.accepts_file('meson.build'))
17 |
18 | def test_scan_file_object(self):
19 | meson_scanner = MesonScanner()
20 | report = Report('/root')
21 | io_object = io.StringIO('xxx')
22 | meson_scanner.scan_file_object(
23 | 'meson.build', io_object, report)
24 | self.assertEqual(len(report.issues), 0)
25 |
26 |
27 | def test_arch_specific_libs_re(self):
28 | match = MesonScanner.ARCH_SPECIFIC_LIBS_RE_PROG.search("cc.find_library('foo')")
29 | self.assertIsNone(match)
30 | match = MesonScanner.ARCH_SPECIFIC_LIBS_RE_PROG.search("cc.find_library('otherarch')")
31 | self.assertIsNotNone(match)
32 | self.assertEqual(match.group(1), "otherarch")
33 |
34 | def test_arch_specific_libs(self):
35 | meson_scanner = MesonScanner()
36 | report = Report('/root')
37 | io_object = io.StringIO("cc.find_library('otherarch')")
38 | meson_scanner.scan_file_object(
39 | 'meson.build', io_object, report)
40 | self.assertEqual(len(report.issues), 1)
41 |
42 | def test_neoverse_specific_opts_line_re(self):
43 | match = MesonScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search("'compiler_options': ['-mcpu=ampere1a'],")
44 | self.assertIsNone(match)
45 | match = MesonScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search("'compiler_options': ['-mcpu=neoverse-n2'],")
46 | self.assertIsNotNone(match)
47 |
48 | def test_ampereone_specific_opts_line_re(self):
49 | match = MesonScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search("'compiler_options': ['-mcpu=neoverse-n2'],")
50 | self.assertIsNone(match)
51 | match = MesonScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search("'compiler_options': ['-mcpu=ampere1a'],")
52 | self.assertIsNotNone(match)
53 |
54 | def test_neoverse_specific_opts_line(self):
55 | meson_scanner = MesonScanner()
56 |
57 | report = Report('/root')
58 | io_object = io.StringIO("'compiler_options': ['-mcpu=neoverse-n2'],")
59 | meson_scanner.scan_file_object(
60 | 'meson.build', io_object, report)
61 | # Should report 2 issues, one for neoverse flag indication, another for ampereone flag missing.
62 | self.assertEqual(len(report.issues), 2)
63 |
64 | report = Report('/root')
65 | io_object = io.StringIO("'compiler_options': ['-mcpu=ampere1a'],\n'compiler_options': ['-mtune=ampere1a'],\n'compiler_options': ['-mcpu=neoverse-v2'],\n'compiler_options': ['-mtune=neoverse-v2'],\n")
66 | meson_scanner.scan_file_object(
67 | 'meson.build', io_object, report)
68 | self.assertEqual(len(report.issues), 2)
69 |
70 |
71 |
--------------------------------------------------------------------------------
/unittest/test_naive_comment_parser.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import unittest
20 | from src.advisor.parsers.naive_comment_parser import NaiveCommentParser
21 |
22 |
23 | class TestNaiveCommentParser(unittest.TestCase):
24 | def test_parse_line(self):
25 | comment_parser = NaiveCommentParser()
26 | self.assertFalse(comment_parser.parse_line('is not a comment'))
27 | self.assertTrue(comment_parser.parse_line('// single line comment'))
28 | self.assertFalse(comment_parser.parse_line('is not a comment'))
29 | self.assertTrue(comment_parser.parse_line('/* start of multi line comment'))
30 | self.assertTrue(comment_parser.parse_line(' middle of multi line comment'))
31 | self.assertTrue(comment_parser.parse_line('end of multi line comment */'))
32 | self.assertFalse(comment_parser.parse_line('is not a comment'))
33 | self.assertTrue(comment_parser.parse_line('/* single line comment */'))
34 | self.assertFalse(comment_parser.parse_line('is not a comment'))
35 | self.assertFalse(comment_parser.parse_line('comment in /* middle of */ line'))
36 |
--------------------------------------------------------------------------------
/unittest/test_port_filter.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2017 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import unittest
20 | from src.advisor.filters.port_filter import PortFilter
21 | from src.advisor.reports.issues.inline_asm_issue import InlineAsmIssue
22 | from src.advisor.reports.report import Report
23 |
24 |
25 | class TestPortFilter(unittest.TestCase):
26 | def test_finalize(self):
27 | report = Report('/root')
28 | port_filter = PortFilter()
29 | port_filter.initialize_report(report)
30 | report.add_source_file('test.c')
31 | report.add_issue(InlineAsmIssue('test.c', 123))
32 | report.add_source_file('test-otherarch.c')
33 | report.add_issue(InlineAsmIssue('test-otherarch.c', 123))
34 | report.add_source_file('test-aarch64.c')
35 | report.add_issue(InlineAsmIssue('test-aarch64.c', 123))
36 | port_filter.finalize_report(report)
37 | self.assertEqual(len(report.issues), 1)
--------------------------------------------------------------------------------
/unittest/test_python_comment_parser.py:
--------------------------------------------------------------------------------
1 | from src.advisor.parsers.python_comment_parser import PythonCommentParser
2 | import unittest
3 |
4 |
5 | class TestPythonCommentParser(unittest.TestCase):
6 | def test_parse_line(self):
7 | comment_parser = PythonCommentParser()
8 | self.assertFalse(comment_parser.parse_line('is not a comment'))
9 | self.assertTrue(comment_parser.parse_line('# single line comment'))
10 | self.assertFalse(comment_parser.parse_line('is not a comment'))
11 | self.assertTrue(comment_parser.parse_line('""" start of multi line comment'))
12 | self.assertTrue(comment_parser.parse_line(' middle of multi line comment'))
13 | self.assertTrue(comment_parser.parse_line('end of multi line comment """'))
14 | self.assertFalse(comment_parser.parse_line('is not a comment'))
15 | self.assertTrue(comment_parser.parse_line('""" single line comment """'))
16 | self.assertFalse(comment_parser.parse_line('is not a comment'))
17 | self.assertFalse(comment_parser.parse_line('comment in """ middle of """ line'))
18 |
--------------------------------------------------------------------------------
/unittest/test_python_requirements_parser.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from src.advisor.parsers.python_requirements_parser import PythonRequirementsParser
3 |
4 |
5 | class TestPythonRequirementsParser(unittest.TestCase):
6 | def setUp(self) -> None:
7 | self.parser = PythonRequirementsParser()
8 |
9 | def test_parse_line_returns_name_version_and_comparer(self):
10 | expected = 'SciPy', '1.7.2', '>='
11 | self.assertEqual(expected, self.parser.parse_line('SciPy>=1.7.2'))
12 | self.assertEqual(expected, self.parser.parse_line('SciPy >= 1.7.2'))
13 |
14 | def test_parse_line_returns_name(self):
15 | expected = 'SciPy', '', ''
16 | self.assertEqual(expected, self.parser.parse_line('SciPy'))
17 |
18 | def test_parse_line_ignores_comments(self):
19 | expected = 'SciPy', '1.7.2', '>='
20 | self.assertEqual(expected, self.parser.parse_line('SciPy>=1.7.2 # this is a comment'))
21 | self.assertEqual(expected, self.parser.parse_line('SciPy >= 1.7.2 # this is a comment'))
--------------------------------------------------------------------------------
/unittest/test_python_version_checker.py:
--------------------------------------------------------------------------------
1 | import pkg_resources
2 | import platform
3 | import unittest
4 | from src.advisor.helpers.python.python_version_checker import PythonVersionChecker
5 |
6 | class TestPythonVersionChecker(unittest.TestCase):
7 | def test_get_package_version_returns_non_empty_string_for_existing_library(self):
8 | pip_version = pkg_resources.get_distribution('Jinja2').version
9 | self.assertEqual(pip_version, PythonVersionChecker.get_package_version('Jinja2'))
10 |
11 | def test_get_package_version_returns_none_for_fake_library(self):
12 | version = PythonVersionChecker.get_package_version('myFakeLibraryThatDoesNotExist')
13 | self.assertIsNone(version)
14 |
15 | def test_get_python_version_returns_current_version(self):
16 | runtime_version = platform.python_version()
17 | self.assertEqual(runtime_version, PythonVersionChecker.get_python_version())
18 |
19 | def test_get_pip_version_returns_current_version(self):
20 | pip_version = pkg_resources.get_distribution('pip').version
21 | self.assertEqual(pip_version, PythonVersionChecker.get_pip_version())
--------------------------------------------------------------------------------
/unittest/test_report_factory.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2020 Arm Ltd.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | SPDX-License-Identifier: Apache-2.0
17 | """
18 |
19 | import unittest
20 | from src.advisor.reports.report_factory import ReportFactory, ReportOutputFormat
21 |
22 |
23 | class TestReportFactory(unittest.TestCase):
24 | def test_output_format_from_extension(self):
25 | report_factory = ReportFactory()
26 | self.assertEqual(report_factory.output_format_for_extension('txt'), ReportOutputFormat.TEXT)
27 | self.assertEqual(report_factory.output_format_for_extension('html'), ReportOutputFormat.HTML)
28 | self.assertEqual(report_factory.output_format_for_extension('htm'), ReportOutputFormat.HTML)
29 | self.assertEqual(report_factory.output_format_for_extension('json'), ReportOutputFormat.JSON)
30 | self.assertEqual(report_factory.output_format_for_extension('csv'), ReportOutputFormat.CSV)
31 |
--------------------------------------------------------------------------------
/unittest/test_ruby_gem_parser.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from src.advisor.parsers.ruby_gem_parser import RubyGemParser
3 |
4 |
5 | class TestRubyGemParser(unittest.TestCase):
6 | def setUp(self) -> None:
7 | self.parser = RubyGemParser()
8 |
9 | def test_gem_with_name_returns_name(self):
10 | expected = 'rails', None
11 | self.assertEqual(expected, self.parser.parse_line('"rails"'))
12 | self.assertEqual(expected, self.parser.parse_line("'rails'"))
13 |
14 | def test_gem_with_name_and_version_returns_name_and_version(self):
15 | expected = 'rails', '6.1.6.1'
16 | self.assertEqual(expected, self.parser.parse_line('"rails", "6.1.6.1"'))
17 | self.assertEqual(expected, self.parser.parse_line("'rails', '6.1.6.1'"))
18 |
19 | def test_gem_with_name_version_and_specifier_returns_name(self):
20 | expected = 'rails', '6.1.6.1'
21 | self.assertEqual(expected, self.parser.parse_line("'rails', '~> 6.1.6.1'"))
22 | self.assertEqual(expected, self.parser.parse_line('"rails", "~> 6.1.6.1"'))
23 | self.assertEqual(expected, self.parser.parse_line('"rails", "<= 6.1.6.1"'))
24 | self.assertEqual(expected, self.parser.parse_line('"rails", ">= 6.1.6.1"'))
25 | self.assertEqual(expected, self.parser.parse_line('"rails", ">= 6.1.6.1", "< 7.0.0"'))
26 |
27 | def test_gem_with_ternary_operator_returns_correct_value(self):
28 | expected = 'cucumber', '4.1'
29 | self.assertEqual(expected, self.parser.parse_line('"cucumber", RUBY_VERSION >= "2.5" ? "~> 5.1.2" : "~> 4.1"'))
30 |
31 | def test_gem_with_other_specifiers_returns_correct_value(self):
32 | expected = 'gssapi', None
33 | self.assertEqual(expected, self.parser.parse_line('"gssapi", group: :kerberos'))
34 | self.assertEqual(expected, self.parser.parse_line('"gssapi", require: false, platform: :mri'))
35 | self.assertEqual(expected, self.parser.parse_line('"gssapi", git: "https://github.com/gssapi"'))
--------------------------------------------------------------------------------
/unittest/test_rules_loader.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from src.advisor.helpers.rules_loader import RulesLoader
3 |
4 | class TestRulesLoader(unittest.TestCase):
5 | def test_get_rules_gets_valid_object_for_existing_rules_file(self):
6 | rules = RulesLoader.get_rules('python')
7 | name = rules['languageRules']['name']
8 | self.assertIsNotNone(rules)
9 | self.assertEqual('Python', name)
10 |
11 | def test_get_rules_gets_none_for_unexisting_file(self):
12 | rules = RulesLoader.get_rules('fake_language')
13 | self.assertIsNone(rules)
--------------------------------------------------------------------------------