613 lines
21 KiB
Python
613 lines
21 KiB
Python
# test_thespacedevs.py
|
|
|
|
import deepdiff
|
|
import pytest
|
|
from agenda.thespacedevs import format_launch_changes
|
|
|
|
# --- Helper Functions for Tests ---
|
|
|
|
|
|
def create_base_launch():
|
|
"""Creates a base launch dictionary for diffing."""
|
|
return {
|
|
"id": "test-id",
|
|
"name": "Starship | Flight 10",
|
|
"status": {
|
|
"id": 8,
|
|
"name": "To Be Confirmed",
|
|
"abbrev": "TBC",
|
|
"description": "Awaiting official confirmation...",
|
|
},
|
|
"last_updated": "2025-08-08T16:03:39Z",
|
|
"net": "2025-08-22T23:30:00Z",
|
|
"window_end": "2025-08-23T01:34:00Z",
|
|
"window_start": "2025-08-22T23:30:00Z",
|
|
"net_precision": {
|
|
"id": 1,
|
|
"name": "Minute",
|
|
"abbrev": "MIN",
|
|
"description": "The T-0 is accurate to the minute.",
|
|
},
|
|
"probability": 75,
|
|
"pad": {
|
|
"id": 188,
|
|
"name": "Orbital Launch Mount A",
|
|
"location": {"name": "SpaceX Starbase, TX, USA"},
|
|
},
|
|
"mission": {
|
|
"name": "Flight 10"
|
|
# description intentionally omitted initially for test_dictionary_item_added
|
|
},
|
|
# Fields that should be skipped
|
|
"agency_launch_attempt_count": 550,
|
|
"location_launch_attempt_count": 18,
|
|
"pad_launch_attempt_count": 9,
|
|
"orbital_launch_attempt_count": 5,
|
|
"agency_launch_attempt_count_year": 100,
|
|
"location_launch_attempt_count_year": 3,
|
|
"pad_launch_attempt_count_year": 3,
|
|
"orbital_launch_attempt_count_year": 1,
|
|
}
|
|
|
|
|
|
# --- Tests for format_launch_changes ---
|
|
|
|
|
|
def test_no_changes():
|
|
"""Test when there are no differences."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert result == "No specific changes detected"
|
|
|
|
|
|
def test_status_change():
|
|
"""Test changes to the status name."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["status"]["name"] = "Go for Launch"
|
|
# Note: ID change might happen, but the test focuses on the name change message
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
# print(f"DEBUG test_status_change diff: {diff}") # Uncomment for debugging
|
|
result = format_launch_changes(diff)
|
|
# DeepDiff should report this as values_changed
|
|
assert "Status changed from 'To Be Confirmed' to 'Go for Launch'" in result
|
|
|
|
|
|
def test_net_precision_change():
|
|
"""Test changes to the net precision name."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["net_precision"]["name"] = "Hour"
|
|
# Note: ID change might happen, but the test focuses on the name change message
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
# print(f"DEBUG test_net_precision_change diff: {diff}") # Uncomment for debugging
|
|
result = format_launch_changes(diff)
|
|
# DeepDiff should report this as values_changed
|
|
assert "Launch precision changed from 'Minute' to 'Hour'" in result
|
|
|
|
|
|
def test_net_change():
|
|
"""Test changes to the net (launch time)."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["net"] = "2025-08-23T00:00:00Z"
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
# The function uses format_date, so the output will be formatted
|
|
assert (
|
|
"Launch time changed from 22 Aug 2025 at 23:30 UTC to 23 Aug 2025 at 00:00 UTC"
|
|
in result
|
|
)
|
|
|
|
|
|
def test_window_start_change():
|
|
"""Test changes to the window start."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["window_start"] = "2025-08-22T23:00:00Z"
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert (
|
|
"Launch window start changed from 22 Aug 2025 at 23:30 UTC to 22 Aug 2025 at 23:00 UTC"
|
|
in result
|
|
)
|
|
|
|
|
|
def test_window_end_change():
|
|
"""Test changes to the window end."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["window_end"] = "2025-08-23T02:00:00Z"
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert (
|
|
"Launch window end changed from 23 Aug 2025 at 01:34 UTC to 23 Aug 2025 at 02:00 UTC"
|
|
in result
|
|
)
|
|
|
|
|
|
def test_last_updated_change():
|
|
"""Test changes to the last updated time."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["last_updated"] = "2025-08-09T10:00:00Z"
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert "Last updated: 09 Aug 2025 at 10:00 UTC" in result
|
|
|
|
|
|
def test_name_change():
|
|
"""Test changes to the launch name."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["name"] = "Starship | Flight 10 - Revised"
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert (
|
|
"Mission name changed from 'Starship | Flight 10' to 'Starship | Flight 10 - Revised'"
|
|
in result
|
|
)
|
|
|
|
|
|
def test_probability_change():
|
|
"""Test changes to the launch probability."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["probability"] = 85
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert "Launch probability changed from 75% to 85%" in result
|
|
|
|
|
|
def test_probability_set():
|
|
"""Test setting probability from None."""
|
|
prev = create_base_launch()
|
|
prev["probability"] = None # Start with None
|
|
cur = create_base_launch() # End with 75 (int)
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert "Launch probability set to 75%" in result
|
|
|
|
|
|
def test_probability_removed():
|
|
"""Test removing probability (setting to None)."""
|
|
prev = create_base_launch() # Start with 75 (int)
|
|
cur = create_base_launch()
|
|
cur["probability"] = None # End with None
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert "Launch probability removed" in result
|
|
|
|
|
|
def test_skip_fields():
|
|
"""Test that specific fields are skipped."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["agency_launch_attempt_count"] = 551
|
|
cur["pad_launch_attempt_count_year"] = 4
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
# The only change is in skipped fields, so no user-facing changes
|
|
assert result == "No specific changes detected"
|
|
|
|
|
|
def test_dictionary_item_added():
|
|
"""Test adding a new field."""
|
|
prev = create_base_launch()
|
|
# Ensure 'description' is not in the base mission dict
|
|
assert "description" not in prev["mission"]
|
|
cur = create_base_launch()
|
|
cur["mission"]["description"] = "New mission description."
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
# print(f"DEBUG test_dictionary_item_added diff: {diff}") # Uncomment for debugging
|
|
result = format_launch_changes(diff)
|
|
# DeepDiff path for nested dict item added
|
|
assert (
|
|
"New field added: Mission['Description" in result
|
|
) # Matches the output format
|
|
|
|
|
|
def test_dictionary_item_removed():
|
|
"""Test removing a field."""
|
|
prev = create_base_launch()
|
|
# Add 'description' to prev so it can be removed
|
|
prev["mission"]["description"] = "Old description."
|
|
cur = create_base_launch()
|
|
# Ensure 'description' is not in cur's mission dict
|
|
assert "description" not in cur["mission"]
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
# print(f"DEBUG test_dictionary_item_removed diff: {diff}") # Uncomment for debugging
|
|
result = format_launch_changes(diff)
|
|
# DeepDiff path for nested dict item removed
|
|
assert "Field removed: Mission['Description" in result # Matches the output format
|
|
|
|
|
|
def test_type_change():
|
|
"""Test changing the type of a field."""
|
|
prev = create_base_launch()
|
|
cur = create_base_launch()
|
|
cur["probability"] = "High" # Change int to string
|
|
diff = deepdiff.DeepDiff(prev, cur, ignore_order=True)
|
|
result = format_launch_changes(diff)
|
|
assert "Probability type changed from int to str" in result
|
|
|
|
|
|
# --- Test with Sample Data (Simulated Diff) ---
|
|
|
|
|
|
def test_with_sample_data_status_change():
|
|
"""Simulate a diff like the one that might occur for status change using sample data structure."""
|
|
# Simulate a diff where status changes from TBC to Success (ID 3)
|
|
# This mimics the EXACT structure DeepDiff produces for values_changed
|
|
# We only include the fields we care about in the test
|
|
sample_diff_status = deepdiff.DeepDiff(
|
|
{"status": {"id": 8, "name": "To Be Confirmed"}},
|
|
{"status": {"id": 3, "name": "Success"}},
|
|
ignore_order=True,
|
|
)
|
|
# print(f"DEBUG test_with_sample_data_status_change diff: {sample_diff_status}") # Debug
|
|
result = format_launch_changes(sample_diff_status)
|
|
# Should report the status name change
|
|
assert "Status changed from 'To Be Confirmed' to 'Success'" in result
|
|
# Ensure it doesn't report ID change separately due to the 'startswith' logic
|
|
# (The logic should group them under the name change)
|
|
# A simple check: if name change is there, and ID is handled, it's likely correct.
|
|
# The exact number of bullet points might vary based on ID/abbrev handling,
|
|
# but the key message should be present.
|
|
|
|
|
|
def test_with_sample_data_net_change():
|
|
"""Simulate a diff for net change."""
|
|
sample_diff_net = {
|
|
"values_changed": {
|
|
"root['net']": {
|
|
"new_value": "2025-08-25T12:00:00Z",
|
|
"old_value": "2025-08-22T23:30:00Z",
|
|
}
|
|
}
|
|
}
|
|
result = format_launch_changes(sample_diff_net)
|
|
assert (
|
|
"Launch time changed from 22 Aug 2025 at 23:30 UTC to 25 Aug 2025 at 12:00 UTC"
|
|
in result
|
|
)
|
|
|
|
|
|
def test_status_name_change():
|
|
diffs = {
|
|
"values_changed": {
|
|
"root['status']['name']": {
|
|
"old_value": "To Be Confirmed",
|
|
"new_value": "Go for Launch",
|
|
}
|
|
}
|
|
}
|
|
out = format_launch_changes(diffs)
|
|
assert "Status changed from 'To Be Confirmed' to 'Go for Launch'" in out
|
|
|
|
|
|
def test_net_precision_change():
|
|
diffs = {
|
|
"values_changed": {
|
|
"root['net_precision']['name']": {
|
|
"old_value": "Hour",
|
|
"new_value": "Minute",
|
|
}
|
|
}
|
|
}
|
|
out = format_launch_changes(diffs)
|
|
assert "Launch precision changed from 'Hour' to 'Minute'" in out
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"field,label",
|
|
[
|
|
("net", "Launch time"),
|
|
("window_start", "Launch window start"),
|
|
("window_end", "Launch window end"),
|
|
],
|
|
)
|
|
def test_datetime_changes_formatted(field: str, label: str):
|
|
diffs = {
|
|
"values_changed": {
|
|
f"root['{field}']": {
|
|
"old_value": "2025-08-22T23:30:00Z",
|
|
"new_value": "2025-08-23T01:34:00Z",
|
|
}
|
|
}
|
|
}
|
|
out = format_launch_changes(diffs)
|
|
assert (
|
|
f"{label} changed from 22 Aug 2025 at 23:30 UTC " f"to 23 Aug 2025 at 01:34 UTC"
|
|
) in out
|
|
|
|
|
|
def test_last_updated_formatted():
|
|
diffs = {
|
|
"values_changed": {
|
|
"root['last_updated']": {
|
|
"old_value": "2025-08-08T16:03:39Z",
|
|
"new_value": "2025-08-09T12:00:00Z",
|
|
}
|
|
}
|
|
}
|
|
out = format_launch_changes(diffs)
|
|
# Only the new value is shown for last_updated
|
|
assert "Last updated: 09 Aug 2025 at 12:00 UTC" in out
|
|
assert "16:03" not in out # ensure old value not included
|
|
|
|
|
|
def test_name_and_probability_changes():
|
|
diffs = {
|
|
"values_changed": {
|
|
"root['name']": {
|
|
"old_value": "Starship | Flight 10",
|
|
"new_value": "Starship | Flight X",
|
|
},
|
|
"root['probability']": {"old_value": 70, "new_value": 85},
|
|
}
|
|
}
|
|
out = format_launch_changes(diffs)
|
|
assert (
|
|
"Mission name changed from 'Starship | Flight 10' to 'Starship | Flight X'"
|
|
in out
|
|
)
|
|
assert "Launch probability changed from 70% to 85%" in out
|
|
|
|
|
|
def test_probability_set_and_removed():
|
|
# Set from None
|
|
diffs_set = {
|
|
"values_changed": {"root['probability']": {"old_value": None, "new_value": 40}}
|
|
}
|
|
out_set = format_launch_changes(diffs_set)
|
|
assert "Launch probability set to 40%" in out_set
|
|
|
|
# Removed to None
|
|
diffs_removed = {
|
|
"values_changed": {"root['probability']": {"old_value": 30, "new_value": None}}
|
|
}
|
|
out_removed = format_launch_changes(diffs_removed)
|
|
assert "Launch probability removed" in out_removed
|
|
|
|
|
|
def test_skipped_fields_are_not_reported():
|
|
diffs = {
|
|
"values_changed": {
|
|
"root['agency_launch_attempt_count']": {
|
|
"old_value": 556,
|
|
"new_value": 557,
|
|
},
|
|
"root['pad_launch_attempt_count_year']": {
|
|
"old_value": 3,
|
|
"new_value": 4,
|
|
},
|
|
}
|
|
}
|
|
out = format_launch_changes(diffs)
|
|
# No bullet points should be produced for skipped fields
|
|
assert out == "No specific changes detected"
|
|
|
|
|
|
def test_generic_value_change_fallback():
|
|
diffs = {
|
|
"values_changed": {
|
|
"root['rocket']['configuration']['variant']": {
|
|
"old_value": "",
|
|
"new_value": "Block 2",
|
|
}
|
|
}
|
|
}
|
|
out = format_launch_changes(diffs)
|
|
assert (
|
|
"rocket']['configuration']['variant'] changed from '' to 'Block 2'" not in out
|
|
) # ensure path cleaning happened
|
|
assert "rocket']['configuration']['variant" not in out # sanity: no stray brackets
|
|
assert "rocket']['configuration']['variant" not in out # redundant but explicit
|
|
# Expected cleaned path from the function logic:
|
|
assert (
|
|
"rocket']['configuration']['variant" not in out
|
|
) # path is cleaned to "rocket']['configuration']['variant"
|
|
# The function replaces prefixes; the fallback prints the cleaned field string:
|
|
# "rocket']['configuration']['variant changed from '' to 'Block 2'"
|
|
# Because there is no special handling for deeper nesting, we assert a substring:
|
|
assert "variant changed from '' to 'Block 2'" in out
|
|
|
|
|
|
def test_dictionary_item_added_removed_and_type_change():
|
|
diffs = {
|
|
"dictionary_item_added": {"root['new_field']"},
|
|
"dictionary_item_removed": {"root['old_field_name']"},
|
|
"type_changes": {
|
|
"root['probability']": {
|
|
"old_type": int,
|
|
"new_type": str,
|
|
"old_value": 70,
|
|
"new_value": "70%",
|
|
}
|
|
},
|
|
}
|
|
out = format_launch_changes(diffs)
|
|
assert "New field added: New Field" in out
|
|
assert "Field removed: Old Field Name" in out
|
|
assert "Probability type changed from int to str" in out
|
|
|
|
|
|
def test_no_changes_message():
|
|
diffs = {}
|
|
out = format_launch_changes(diffs)
|
|
assert out == "No specific changes detected"
|
|
|
|
|
|
def test_no_changes():
|
|
"""
|
|
Tests that no message is generated when there are no differences.
|
|
"""
|
|
old_launch = {"id": 1, "name": "Launch A"}
|
|
new_launch = {"id": 1, "name": "Launch A"}
|
|
diff = deepdiff.DeepDiff(old_launch, new_launch)
|
|
assert format_launch_changes(diff) == "No specific changes detected"
|
|
|
|
|
|
def test_mission_name_change():
|
|
"""
|
|
Tests a simple change to the mission name.
|
|
"""
|
|
old_launch = {"name": "Starship | Flight 9"}
|
|
new_launch = {"name": "Starship | Flight 10"}
|
|
diff = deepdiff.DeepDiff(old_launch, new_launch)
|
|
expected = "• Mission name changed from 'Starship | Flight 9' to 'Starship | Flight 10'"
|
|
assert format_launch_changes(diff) == expected
|
|
|
|
|
|
def test_status_change():
|
|
"""
|
|
Tests that a change in status name is formatted correctly and that other
|
|
changes within the 'status' dictionary are ignored for a cleaner output.
|
|
"""
|
|
old_launch = {"status": {"id": 8, "name": "To Be Confirmed", "abbrev": "TBC"}}
|
|
new_launch = {"status": {"id": 1, "name": "Go for Launch", "abbrev": "Go"}}
|
|
diff = deepdiff.DeepDiff(old_launch, new_launch)
|
|
expected = "• Status changed from 'To Be Confirmed' to 'Go for Launch'"
|
|
assert format_launch_changes(diff) == expected
|
|
|
|
|
|
def test_datetime_changes():
|
|
"""
|
|
Tests the custom formatting for various datetime fields.
|
|
"""
|
|
old_launch = {
|
|
"net": "2025-08-22T23:30:00Z",
|
|
"window_start": "2025-08-22T23:30:00Z",
|
|
"window_end": "2025-08-23T01:34:00Z",
|
|
"last_updated": "2025-08-08T16:03:39Z",
|
|
}
|
|
new_launch = {
|
|
"net": "2025-08-23T00:00:00Z",
|
|
"window_start": "2025-08-23T00:00:00Z",
|
|
"window_end": "2025-08-23T02:00:00Z",
|
|
"last_updated": "2025-08-09T10:00:00Z",
|
|
}
|
|
diff = deepdiff.DeepDiff(old_launch, new_launch)
|
|
result_lines = format_launch_changes(diff).split("\n")
|
|
|
|
expected_changes = [
|
|
"• Launch time changed from 22 Aug 2025 at 23:30 UTC to 23 Aug 2025 at 00:00 UTC",
|
|
"• Launch window start changed from 22 Aug 2025 at 23:30 UTC to 23 Aug 2025 at 00:00 UTC",
|
|
"• Launch window end changed from 23 Aug 2025 at 01:34 UTC to 23 Aug 2025 at 02:00 UTC",
|
|
"• Last updated: 09 Aug 2025 at 10:00 UTC",
|
|
]
|
|
|
|
assert len(result_lines) == len(expected_changes)
|
|
for expected_line in expected_changes:
|
|
assert expected_line in result_lines
|
|
|
|
|
|
def test_datetime_change_fallback():
|
|
"""
|
|
Tests the fallback for malformed datetime strings.
|
|
"""
|
|
old_launch = {"net": "an-invalid-date"}
|
|
new_launch = {"net": "another-invalid-date"}
|
|
diff = deepdiff.DeepDiff(old_launch, new_launch)
|
|
expected = "• Launch time changed from an-invalid-date to another-invalid-date"
|
|
assert format_launch_changes(diff) == expected
|
|
|
|
|
|
def test_probability_changes():
|
|
"""
|
|
Tests the three scenarios for probability changes:
|
|
1. From a value to another value.
|
|
2. From None to a value.
|
|
3. From a value to None.
|
|
"""
|
|
# From value to value
|
|
old = {"probability": 70}
|
|
new = {"probability": 80}
|
|
diff = deepdiff.DeepDiff(old, new)
|
|
assert format_launch_changes(diff) == "• Launch probability changed from 70% to 80%"
|
|
|
|
# From None to value
|
|
old = {"probability": None}
|
|
new = {"probability": 90}
|
|
diff = deepdiff.DeepDiff(old, new)
|
|
assert format_launch_changes(diff) == "• Launch probability set to 90%"
|
|
|
|
# From value to None
|
|
old = {"probability": 90}
|
|
new = {"probability": None}
|
|
diff = deepdiff.DeepDiff(old, new)
|
|
assert format_launch_changes(diff) == "• Launch probability removed"
|
|
|
|
|
|
def test_skipped_field_is_ignored():
|
|
"""
|
|
Tests that changes to fields in the SKIP_FIELDS list are ignored.
|
|
"""
|
|
old = {"pad_launch_attempt_count_year": 4}
|
|
new = {"pad_launch_attempt_count_year": 5}
|
|
diff = deepdiff.DeepDiff(old, new)
|
|
assert format_launch_changes(diff) == "No specific changes detected"
|
|
|
|
|
|
def test_dictionary_item_added():
|
|
"""
|
|
Tests that newly added fields are reported.
|
|
"""
|
|
old = {"name": "Launch"}
|
|
new = {"name": "Launch", "hashtag": "#launchday"}
|
|
diff = deepdiff.DeepDiff(old, new)
|
|
assert format_launch_changes(diff) == "• New field added: Hashtag"
|
|
|
|
|
|
def test_dictionary_item_removed():
|
|
"""
|
|
Tests that removed fields are reported.
|
|
"""
|
|
old = {"name": "Launch", "hashtag": "#launchday"}
|
|
new = {"name": "Launch"}
|
|
diff = deepdiff.DeepDiff(old, new)
|
|
assert format_launch_changes(diff) == "• Field removed: Hashtag"
|
|
|
|
|
|
def test_type_change():
|
|
"""
|
|
Tests that a change in the data type of a field is reported.
|
|
"""
|
|
old = {"probability": 50}
|
|
new = {"probability": "50%"}
|
|
diff = deepdiff.DeepDiff(old, new)
|
|
assert format_launch_changes(diff) == "• Probability type changed from int to str"
|
|
|
|
|
|
def test_multiple_changes():
|
|
"""
|
|
Tests a scenario with multiple, mixed changes to ensure all are reported.
|
|
Order is not guaranteed, so we check for the presence of each line.
|
|
"""
|
|
old_launch = {
|
|
"status": {"name": "To Be Confirmed"},
|
|
"probability": 90,
|
|
"name": "Old Mission Name",
|
|
}
|
|
new_launch = {
|
|
"status": {"name": "Go for Launch"},
|
|
"name": "New Mission Name",
|
|
"weather_concerns": "High winds.",
|
|
}
|
|
diff = deepdiff.DeepDiff(old_launch, new_launch)
|
|
result_lines = format_launch_changes(diff).split("\n")
|
|
|
|
expected_changes = [
|
|
"• Status changed from 'To Be Confirmed' to 'Go for Launch'",
|
|
"• Mission name changed from 'Old Mission Name' to 'New Mission Name'",
|
|
"• Field removed: Probability",
|
|
"• New field added: Weather Concerns",
|
|
]
|
|
|
|
assert len(result_lines) == len(expected_changes)
|
|
for expected_line in expected_changes:
|
|
assert expected_line in result_lines
|