diff --git a/lib/cc/engine/analyzers/python/parser.py b/lib/cc/engine/analyzers/python/parser.py index bc98bc4f..b66541a8 100644 --- a/lib/cc/engine/analyzers/python/parser.py +++ b/lib/cc/engine/analyzers/python/parser.py @@ -7,9 +7,9 @@ def string_type(): def num_types(): if PY3: - return (int, float, complex) + return (int, float) else: - return (int, float, long, complex) + return (int, float, long) def to_json(node): json_ast = {'attributes': {}} @@ -31,6 +31,10 @@ def cast_value(value): return value elif PY3 and isinstance(value, bytes): return value.decode() + elif isinstance(value, complex): + # Complex numbers cannot be serialised directly. Ruby's to_json + # handles this by string-ifying the numbers, so we do similarly here. + return str(complex) elif isinstance(value, num_types()): if abs(value) == 1e3000: return cast_infinity(value) diff --git a/spec/cc/engine/analyzers/python/main_spec.rb b/spec/cc/engine/analyzers/python/main_spec.rb index d250f4e2..73b91cdf 100644 --- a/spec/cc/engine/analyzers/python/main_spec.rb +++ b/spec/cc/engine/analyzers/python/main_spec.rb @@ -111,6 +111,53 @@ def b(thing: str): expect(json["severity"]).to eq(CC::Engine::Analyzers::Base::MAJOR) end + it "finds duplication with complex-number literals" do + create_source_file("complex.py", <<-EOJS) +def a(): + return 1+1j + +def b(): + return 1 + 1J + +def c(): + return (1 + 1j) + +def d(): + return 1 + EOJS + + conf = CC::Engine::Analyzers::EngineConfig.new({ + "config" => { + "languages" => { + "python" => { + "mass_threshold" => 4, + "python_version" => 3, + }, + }, + }, + }) + issues = run_engine(conf).strip.split("\0") + result = issues.first.strip + json = JSON.parse(result) + + expect(json["type"]).to eq("issue") + expect(json["check_name"]).to eq("similar-code") + expect(json["description"]).to eq("Similar blocks of code found in 3 locations. Consider refactoring.") + expect(json["categories"]).to eq(["Duplication"]) + expect(json["location"]).to eq({ + "path" => "complex.py", + "lines" => { "begin" => 1, "end" => 2 }, + }) + expect(json["remediation_points"]).to eq(750_000) + expect(json["other_locations"]).to eq([ + {"path" => "complex.py", "lines" => { "begin" => 4, "end" => 5 } }, + {"path" => "complex.py", "lines" => { "begin" => 7, "end" => 8 } }, + ]) + expect(json["content"]["body"]).to match(/This issue has a mass of 13/) + expect(json["fingerprint"]).to eq("f867cd91cfb73d925510a79a58619d1a") + expect(json["severity"]).to eq(CC::Engine::Analyzers::Base::MAJOR) + end + it "skips unparsable files" do create_source_file("foo.py", <<-EOPY) ---