blob: 7d9b3a0eb44fe9b5ac45412be9ef2f2792bef073 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2025 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import unittest
import os
import tempfile
import shutil
import bedrock_metrics
class TestBedrockMetrics(unittest.TestCase):
def setUp(self):
# Create a temporary directory for test files.
self.test_dir = tempfile.mkdtemp(prefix="bedrock_test_")
self.sub_dir = os.path.join(self.test_dir, "sub")
os.makedirs(self.sub_dir)
# --- Files for count_matching_files ---
# Structure:
# self.test_dir/
# - file_alpha.h (Content: "apple banana\ncount_me_once")
# - file_beta.cc (Content: "banana cherry\ncount_me_once\ncount_me_once")
# - file_gamma.mm (Content: "apple cherry\nno_count_string")
# - sub/
# - file_delta.h (Content: "apple\ncount_me_once")
# - file_exclude_me.cc (Content: "apple banana\ncontent for exclude")
# - other_extension.txt (Content: "apple banana\ntext file content")
# - empty_file.h (Content: "")
files_to_create_for_matching = [
("file_alpha.h", "apple banana\ncount_me_once"),
("file_beta.cc", "banana cherry\ncount_me_once\ncount_me_once"),
("file_gamma.mm", "apple cherry\nno_count_string"),
(os.path.join("sub", "file_delta.h"), "apple\ncount_me_once"),
("file_exclude_me.cc", "apple banana\ncontent for exclude"),
("other_extension.txt",
"apple banana\ntext file content"), # Invalid extension
("empty_file.h", "")
]
for rel_path, content in files_to_create_for_matching:
full_path = os.path.join(self.test_dir, rel_path)
os.makedirs(os.path.dirname(full_path), exist_ok=True)
with open(full_path, 'w', encoding='utf-8') as f:
f.write(content)
# --- Files for count_lines ---
self.lines_file1_path = os.path.join(self.test_dir, "lines_file1.data")
with open(self.lines_file1_path, 'w', encoding='utf-8') as f:
f.write("line1\nline2\nline3") # 3 lines
self.lines_file2_path = os.path.join(self.test_dir, "lines_file2.data")
with open(self.lines_file2_path, 'w', encoding='utf-8') as f:
f.write("single line") # 1 line
self.lines_empty_file_path = os.path.join(self.test_dir, "lines_empty.data")
with open(self.lines_empty_file_path, 'w', encoding='utf-8') as f:
f.write("") # 0 lines
def tearDown(self):
# Remove the temporary directory and its contents after tests.
shutil.rmtree(self.test_dir)
# --- Tests for count_matching_files ---
def test_cmf_no_filters_counts_valid_extensions(self):
# Expected: file_alpha.h, file_beta.cc, file_gamma.mm, sub/file_delta.h,
# file_exclude_me.cc, empty_file.h (6 files with .h, .cc, .mm)
# other_extension.txt is ignored due to extension.
# No content_match_strings, so string_matches_count is 0.
count, str_count = bedrock_metrics.count_matching_files(self.test_dir)
self.assertEqual(count, 6, "File count mismatch with no filters")
self.assertEqual(str_count, 0,
"String count should be 0 with no content search strings")
def test_cmf_include_filename_single(self):
# include_filename_strings=["alpha"] -> matches file_alpha.h
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, include_filename_strings=["alpha"])
self.assertEqual(count, 1)
self.assertEqual(str_count, 0)
def test_cmf_include_filename_multiple_all_match(self):
# include_filename_strings=["file", "alpha"] -> matches file_alpha.h
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, include_filename_strings=["file", "alpha"])
self.assertEqual(count, 1)
self.assertEqual(str_count, 0)
def test_cmf_include_filename_multiple_one_no_match(self):
# include_filename_strings=["alpha", "beta"] -> No file has BOTH "alpha"
# AND"beta".
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, include_filename_strings=["alpha", "nomatch"])
self.assertEqual(count, 0)
self.assertEqual(str_count, 0)
def test_cmf_exclude_filename_single(self):
# exclude_filename_strings=["exclude"] -> Excludes file_exclude_me.cc
# Original 6 valid files - 1 = 5 files.
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, exclude_filename_strings=["exclude"])
self.assertEqual(count, 5)
self.assertEqual(str_count, 0)
# These tests verify the current code behavior (ANY).
def test_cmf_include_file_content_strings_any_behavior_one_present(self):
# include_file_content_strings=["apple"]
# Matches: file_alpha.h, file_gamma.mm, sub/file_delta.h, file_exclude_me.cc
# (4 files)
# file_beta.cc (banana cherry) does not contain "apple". empty_file.h is
# empty.
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, include_file_content_strings=["apple"])
self.assertEqual(count, 4)
self.assertEqual(str_count, 0)
def test_cmf_include_file_content_strings_any_behavior_multiple_options(self):
# include_file_content_strings=["apple", "cherry"] (any of these in content)
# file_alpha.h ("apple") - Yes
# file_beta.cc ("cherry") - Yes
# file_gamma.mm ("apple", "cherry") - Yes
# sub/file_delta.h ("apple") - Yes
# file_exclude_me.cc ("apple") - Yes
# empty_file.h - No
# Expected: 5 files
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, include_file_content_strings=["apple", "cherry"])
self.assertEqual(count, 5)
self.assertEqual(str_count, 0)
def test_cmf_include_file_content_strings_none_present_in_content(self):
# include_file_content_strings=["nonexistent_string_pattern"]
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir,
include_file_content_strings=["nonexistent_string_pattern"])
self.assertEqual(count, 0)
self.assertEqual(str_count, 0)
def test_cmf_content_match_strings_single_term_count(self):
# content_match_strings=["count_me_once"]
# All 6 valid files are checked for content counts.
# file_alpha.h: 1 | file_beta.cc: 2 | file_gamma.mm: 0
# sub/file_delta.h: 1 | file_exclude_me.cc: 0 | empty_file.h: 0
# Total string matches: 1 + 2 + 0 + 1 + 0 + 0 = 4
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, content_match_strings=["count_me_once"])
self.assertEqual(
count, 6,
"File count should include all valid files for content counting")
self.assertEqual(str_count, 4, "String match count error")
def test_cmf_content_match_strings_multiple_terms_count(self):
# content_match_strings=["apple", "banana"]
# All 6 valid files are checked.
# file_alpha.h ("apple banana"): apple(1)+banana(1)=2
# file_beta.cc ("banana cherry"): apple(0)+banana(1)=1
# file_gamma.mm ("apple cherry"): apple(1)+banana(0)=1
# sub/file_delta.h ("apple"): apple(1)+banana(0)=1
# file_exclude_me.cc ("apple banana"): apple(1)+banana(1)=2
# empty_file.h: apple(0)+banana(0)=0
# Total string matches: 2+1+1+1+2+0 = 7
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, content_match_strings=["apple", "banana"])
self.assertEqual(count, 6)
self.assertEqual(str_count, 7)
def test_cmf_all_filters_combined(self):
# include_filename_strings=["file"], exclude_filename_strings=["exclude"]
# include_file_content_strings=["apple"] (content filter, using 'any' logic
# of code)
# content_match_strings=["count_me_once"]
# 1. Include "file": file_alpha.h, file_beta.cc, file_gamma.mm,
# file_exclude_me.cc, empty_file.h
# 2. Exclude "exclude": Removes file_exclude_me.cc.
# Remaining: file_alpha.h, file_beta.cc, file_gamma.mm, empty_file.h
# 3. include_file_content_strings=["apple"]: (file must contain "apple")
# file_alpha.h (has "apple") - Keep
# file_beta.cc (no "apple") - Remove
# file_gamma.mm (has "apple") - Keep
# sub/file_delta.h (has "apple"): - Keep
# empty_file.h (no "apple") - Remove
# Matched files: file_alpha.h, file_gamma.mm. So, count = 2.
# 4. content_match_strings=["count_me_once"] on these 2 files:
# file_alpha.h: 1 occurrence
# file_gamma.mm: 0 occurrences
# sub/file_delta.h (has "apple"): 1 occurrences
# Total str_count = 1.
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir,
include_file_content_strings=["apple"],
content_match_strings=["count_me_once"],
include_filename_strings=["file"],
exclude_filename_strings=["exclude"])
self.assertEqual(count, 3)
self.assertEqual(str_count, 2)
def test_cmf_empty_directory(self):
empty_subdir_path = os.path.join(self.test_dir, "empty_subdir_for_test")
os.makedirs(empty_subdir_path)
count, str_count = bedrock_metrics.count_matching_files(empty_subdir_path)
self.assertEqual(count, 0)
self.assertEqual(str_count, 0)
def test_cmf_no_matching_extension_files_present(self):
# Directory with only a .txt file, which is not in [.h, .cc, .mm]
other_ext_dir = os.path.join(self.test_dir, "other_ext_dir")
os.makedirs(other_ext_dir)
with open(os.path.join(other_ext_dir, "somefile.txt"), 'w') as f:
f.write("content")
count, str_count = bedrock_metrics.count_matching_files(other_ext_dir)
self.assertEqual(count, 0)
self.assertEqual(str_count, 0)
def test_cmf_include_file_content_strings_is_empty_list(self):
# An empty list for include_file_content_strings means the content filter
# (Step 4) is skipped.
# Same as include_file_content_strings=None.
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, include_file_content_strings=[])
self.assertEqual(count, 6) # All 6 valid extension files
self.assertEqual(str_count, 0)
def test_cmf_content_match_strings_is_empty_list(self):
# No strings to count, so str_count should be 0.
# File count reflects all files matching other criteria.
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, content_match_strings=[])
self.assertEqual(count, 6) # All 6 valid extension files
self.assertEqual(str_count, 0)
def test_cmf_content_match_strings_includes_empty_string(self):
# The code `if s_str:` skips empty strings in content_match_strings.
# So, ["count_me_once", ""] should behave like ["count_me_once"].
count, str_count = bedrock_metrics.count_matching_files(
self.test_dir, content_match_strings=["count_me_once", ""])
self.assertEqual(count, 6)
self.assertEqual(str_count, 4) # Same as just ["count_me_once"]
# --- Tests for count_lines ---
def test_cl_single_file_multiple_lines(self):
self.assertEqual(bedrock_metrics.count_lines([self.lines_file1_path]), 3)
def test_cl_single_file_one_line_no_trailing_newline(self):
self.assertEqual(bedrock_metrics.count_lines([self.lines_file2_path]), 1)
def test_cl_multiple_files(self):
total_lines = bedrock_metrics.count_lines(
[self.lines_file1_path, self.lines_file2_path])
self.assertEqual(total_lines, 3 + 1) # 4
def test_cl_empty_file(self):
# An empty file has 0 lines according to file.readlines().
self.assertEqual(bedrock_metrics.count_lines([self.lines_empty_file_path]),
0)
def test_cl_mixed_files_including_empty(self):
total_lines = bedrock_metrics.count_lines([
self.lines_file1_path, self.lines_empty_file_path, self.lines_file2_path
])
self.assertEqual(total_lines, 3 + 0 + 1) # 4
def test_cl_empty_file_list(self):
self.assertEqual(bedrock_metrics.count_lines([]), 0)
if __name__ == '__main__':
unittest.main(verbosity=2)