blob: dda2c26db66943dd6a85372dd7dab5fca310df58 [file]
# -------------------------------------------------------------
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# -------------------------------------------------------------
#
# Unit tests for the pure logic in dev/format_changed.py (the line-scoping math,
# hunk parsing, and exclude matching). Run with: python -m pytest dev/tests
#
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import format_changed as fc # noqa: E402
# --- overlaps: replace/delete regions vs edited ranges -------------------------
def test_overlaps_replace_region_hits_and_misses():
# replace of original lines 5..7 -> 0-based half-open [4, 7)
assert fc.overlaps(4, 7, [(6, 6)]) is True # inside
assert fc.overlaps(4, 7, [(5, 5)]) is True # first line of region
assert fc.overlaps(4, 7, [(7, 7)]) is True # last line of region
assert fc.overlaps(4, 7, [(4, 4)]) is False # one before
assert fc.overlaps(4, 7, [(8, 8)]) is False # one after
assert fc.overlaps(4, 7, [(1, 2)]) is False # entirely before
assert fc.overlaps(4, 7, [(8, 9)]) is False # entirely after
def test_overlaps_multiple_ranges():
assert fc.overlaps(4, 7, [(1, 2), (7, 9)]) is True
assert fc.overlaps(4, 7, [(1, 2), (10, 11)]) is False
# --- overlaps: pure insertions (i1 == i2) -------------------------------------
def test_overlaps_pure_insertion_boundaries():
# insertion at 0-based index 5 = between 1-based lines 5 and 6
assert fc.overlaps(5, 5, [(5, 5)]) is True # i1 == e
assert fc.overlaps(5, 5, [(6, 6)]) is True # i1 == s - 1
assert fc.overlaps(5, 5, [(7, 7)]) is False # below the range
assert fc.overlaps(5, 5, [(3, 4)]) is False # above the range
assert fc.overlaps(0, 0, [(1, 1)]) is True # insert before the first line
# --- _hunk_range / parse_hunks ------------------------------------------------
def test_hunk_range_multiline():
assert fc._hunk_range("@@ -1,3 +10,4 @@") == (10, 13)
def test_hunk_range_missing_count_defaults_to_one():
assert fc._hunk_range("@@ -0,0 +5 @@") == (5, 5)
def test_hunk_range_pure_deletion_is_none():
assert fc._hunk_range("@@ -4,2 +3,0 @@") is None
def test_hunk_range_non_header_is_none():
assert fc._hunk_range("+ some added line") is None
assert fc._hunk_range("public int mul(int a) {") is None
def test_parse_hunks_collects_all_ranges():
diff = (
"diff --git a/X.java b/X.java\n"
"--- a/X.java\n"
"+++ b/X.java\n"
"@@ -1,1 +1,1 @@\n"
"-a\n+a \n"
"@@ -10,0 +11,2 @@\n"
"+x\n+y\n"
"@@ -20,2 +22,0 @@\n" # pure deletion -> skipped
)
assert fc.parse_hunks(diff) == [(1, 1), (11, 12)]
# --- exclude matching ---------------------------------------------------------
def test_is_excluded_by_full_path():
p = "src/main/java/org/apache/sysds/conf/DMLConfig.java"
assert fc.is_excluded(p, [p]) is True
def test_is_excluded_by_basename_glob():
p = "src/main/java/org/apache/sysds/conf/DMLConfig.java"
assert fc.is_excluded(p, ["*DMLConfig.java"]) is True
def test_is_excluded_no_match():
assert fc.is_excluded("src/main/java/Foo.java", ["*DMLConfig.java"]) is False
assert fc.is_excluded("src/main/java/Foo.java", []) is False
def test_load_excludes_skips_comments_and_blanks(tmp_path, monkeypatch):
f = tmp_path / "exclude.txt"
f.write_text("# a comment\n\n \nsrc/main/java/Foo.java\n *Bar.java \n",
encoding="utf-8")
monkeypatch.setattr(fc, "EXCLUDE_FILE", str(f))
assert fc.load_excludes() == ["src/main/java/Foo.java", "*Bar.java"]
def test_load_excludes_missing_file_returns_empty(tmp_path, monkeypatch):
monkeypatch.setattr(fc, "EXCLUDE_FILE", str(tmp_path / "does-not-exist.txt"))
assert fc.load_excludes() == []
# --- strip_src_prefix ---------------------------------------------------------
def test_strip_src_prefix():
assert fc.strip_src_prefix("src/main/java/org/A.java") == "org/A.java"
assert fc.strip_src_prefix("src/test/java/org/A.java") == "org/A.java"
# --- line_scoped_result: only edited-line formatting is kept ------------------
def test_line_scoped_result_keeps_only_edited_lines():
# lines 1 and 3 are mis-formatted; an unchanged line 2 separates them so
# difflib yields distinct hunks. Only line 3 is "edited", so line 1 (a
# pre-existing violation the PR did not touch) must stay original.
original = "int a=1;\nint ok = 0;\nint b=2;\n"
formatted = "int a = 1;\nint ok = 0;\nint b = 2;\n"
result, kept = fc.line_scoped_result(original, formatted, [(3, 3)])
assert result == "int a=1;\nint ok = 0;\nint b = 2;\n"
assert len(kept) == 1
def test_line_scoped_result_no_edited_lines_is_noop():
original = "int a=1;\nint b=2;\n"
formatted = "int a = 1;\nint b = 2;\n"
result, kept = fc.line_scoped_result(original, formatted, [])
assert result == original
assert kept == []