Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Ignore missing trailing EOL" option to Compare settings #2573

Merged
merged 25 commits into from
Dec 24, 2024

Conversation

sdottaka
Copy link
Member

@sdottaka sdottaka commented Dec 11, 2024

This PR adds a new option, Ignore missing trailing EOL, to the Compare/General category in the Options window.

When this option is enabled, if one file ends with a newline character (CR, LF, or CRLF) while the other file does not have a trailing newline, the difference in the trailing newline is ignored as long as the content of the last line is identical in both files.

refs #203, #989, #2317

Comment on lines 598 to 800
}

{// diff left: no EOL - right: CR+A
std::vector<char> buf_left(WMCMPBUFF * 2 - 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_right[buf_right.size() - 2] = '\r';
buf_right[buf_right.size() - 1] = 'A';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}
}

for (int i = 0; i < 3; i++)
{
{// diff left: LF+LF - right: no EOL
std::vector<char> buf_left(WMCMPBUFF * 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 - 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_left[buf_left.size() - 2] = '\n';
buf_left[buf_left.size() - 1] = '\n';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}

{// diff left: no EOL - right: LF+LF
std::vector<char> buf_left(WMCMPBUFF * 2 - 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_right[buf_right.size() - 2] = '\n';
buf_right[buf_right.size() - 1] = '\n';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}
}

for (int i = 0; i < 3; i++)
{
{// diff left: CR+CR - right: no EOL
std::vector<char> buf_left(WMCMPBUFF * 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 - 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_left[buf_left.size() - 2] = '\r';
buf_left[buf_left.size() - 1] = '\r';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}

{// diff left: no EOL - right: CR+CR
std::vector<char> buf_left(WMCMPBUFF * 2 - 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_right[buf_right.size() - 2] = '\r';
buf_right[buf_right.size() - 1] = '\r';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}
}

}

Check notice

Code scanning / CodeQL

Block with too many statements Note

Block with too many statements (6 complex statements in the block).
Src/CompareEngines/ByteComparator.cpp Fixed Show fixed Hide fixed
Src/CompareEngines/ByteComparator.cpp Fixed Show fixed Hide fixed
Src/CompareEngines/ByteComparator.cpp Fixed Show fixed Hide fixed
Src/CompareEngines/ByteComparator.cpp Fixed Show fixed Hide fixed
Src/CompareEngines/ByteComparator.cpp Fixed Show fixed Hide fixed
Src/CompareEngines/ByteComparator.cpp Fixed Show fixed Hide fixed
Comment on lines 802 to 1007
EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}

{// diff left: no EOL - right: CR+A
std::vector<char> buf_left(WMCMPBUFF * 2 - 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_right[buf_right.size() - 2] = '\r';
buf_right[buf_right.size() - 1] = 'A';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}
}

for (int i = 0; i < 3; i++)
{
{// diff left: LF+LF - right: no EOL
std::vector<char> buf_left(WMCMPBUFF * 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 - 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_left[buf_left.size() - 2] = '\n';
buf_left[buf_left.size() - 1] = '\n';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}

{// diff left: no EOL - right: LF+LF
std::vector<char> buf_left(WMCMPBUFF * 2 - 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_right[buf_right.size() - 2] = '\n';
buf_right[buf_right.size() - 1] = '\n';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}
}

for (int i = 0; i < 3; i++)
{
{// diff left: CR+CR - right: no EOL
std::vector<char> buf_left(WMCMPBUFF * 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 - 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_left[buf_left.size() - 2] = '\r';
buf_left[buf_left.size() - 1] = '\r';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}

{// diff left: no EOL - right: CR+CR
std::vector<char> buf_left(WMCMPBUFF * 2 - 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_right[buf_right.size() - 2] = '\r';
buf_right[buf_right.size() - 1] = '\r';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}
}
}

Check notice

Code scanning / CodeQL

Block with too many statements Note

Block with too many statements (6 complex statements in the block).
@@ -353,6 +355,8 @@
if ((!m_eol0 || !m_eol1) && (orig0 == end0 || orig1 == end1))
{
// one side had an end-of-line, but the other didn't
ptr0 = ptr0b;

Check warning

Code scanning / CodeQL

Local variable address stored in non-local memory Warning

A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
@@ -353,6 +355,8 @@
if ((!m_eol0 || !m_eol1) && (orig0 == end0 || orig1 == end1))
{
// one side had an end-of-line, but the other didn't
ptr0 = ptr0b;
ptr1 = ptr1b;

Check warning

Code scanning / CodeQL

Local variable address stored in non-local memory Warning

A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
A stack address which arrived via a
parameter
may be assigned to a non-local variable.
Comment on lines +183 to +187
if ((eof[0] || eof[1]) &&
((end0 - ptr0 <= 1 && (lasteol[0] == "\r" || lasteol[0] == "\n" || lasteol[0] == "\r\n") && (end1 == ptr1))) ||
((end0 - ptr0 == 2 && (lasteol[0] == "\r\n") && (end1 == ptr1))) ||
((end1 - ptr1 <= 1 && (lasteol[1] == "\r" || lasteol[1] == "\n" || lasteol[1] == "\r\n") && (end0 == ptr0))) ||
((end1 - ptr1 == 2 && (lasteol[1] == "\r\n") && (end0 == ptr0))))

Check notice

Code scanning / CodeQL

Complex condition Note

Complex condition: too many logical operations in this expression.
Comment on lines 1188 to 1529

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}

{// diff left: no EOL - right: CR+CR
std::vector<char> buf_left(WMCMPBUFF * 2 - 2 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 - 2 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_right[10] = '\n';
buf_left[10] = '\n';
buf_left[11] = '\n';

buf_right[19] = '\n';
buf_left[20] = '\n';
buf_left[21] = '\n';

buf_right[buf_right.size() - 2] = '\r';
buf_right[buf_right.size() - 1] = '\r';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}
}

for (int i = 0; i < 4; i++)
{
{// diff left: CRLF+CRLF - right: no EOL
std::vector<char> buf_left(WMCMPBUFF * 2 - 4 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 - 4 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_left[10] = '\n';
buf_right[10] = '\n';
buf_right[11] = '\n';

buf_left[19] = '\n';
buf_right[20] = '\n';
buf_right[21] = '\n';

buf_left[28] = '\n';
buf_right[30] = '\n';
buf_right[31] = '\n';

buf_left[buf_left.size() - 4] = '\r';
buf_left[buf_left.size() - 3] = '\n';
buf_left[buf_left.size() - 2] = '\r';
buf_left[buf_left.size() - 1] = '\n';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}

{// diff left: no EOL - right: CRLF+CRLF
std::vector<char> buf_left(WMCMPBUFF * 2 - 4 + i);
std::vector<char> buf_right(WMCMPBUFF * 2 - 4 + i);

memset(buf_left.data(), 'A', buf_left.size());
memset(buf_right.data(), 'A', buf_right.size());

buf_right[10] = '\n';
buf_left[10] = '\n';
buf_left[11] = '\n';

buf_right[19] = '\n';
buf_left[20] = '\n';
buf_left[21] = '\n';

buf_right[28] = '\n';
buf_left[30] = '\n';
buf_left[31] = '\n';

buf_right[buf_right.size() - 4] = '\r';
buf_right[buf_right.size() - 3] = '\n';
buf_right[buf_right.size() - 2] = '\r';
buf_right[buf_right.size() - 1] = '\n';

TempFile file_left(filename_left, buf_left.data(), buf_left.size());
TempFile file_right(filename_right, buf_right.data(), buf_right.size());

FilePair pair(filename_left, filename_right);

EXPECT_EQ(DIFFCODE::TEXT | DIFFCODE::DIFF, bc.CompareFiles(&pair.diffData));
}
}
}

Check notice

Code scanning / CodeQL

Block with too many statements Note

Block with too many statements (6 complex statements in the block).
@@ -95,6 +95,124 @@
}
}

TEST(DiffWrapper, RunFileDiff_IgnoreMissingTrailingEol)

Check warning

Code scanning / CodeQL

Poorly documented large function Warning

Poorly documented function: fewer than 2% comments for a function of 117 lines.
@sdottaka sdottaka changed the title WIP Add "Ignore missing trailing EOL" option to Compare settings Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant