-
Notifications
You must be signed in to change notification settings - Fork 7
Variability-aware patching of software product-line variants #179
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
Open
piameier
wants to merge
164
commits into
VariantSync:thesis_pm
Choose a base branch
from
piameier:prototyping
base: thesis_pm
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
164 commits
Select commit
Hold shift + click to select a range
1b54094
basic patching idea
piameier 692d6c6
code refactoring
piameier c35bebc
fixed bugs
piameier 91f3ffa
find insert position for ADD and check neigbors for REM
piameier 24cf2bf
refactoring checkNeighbors method
piameier 1b59508
refactoring findInsertPosition method and formatting code
piameier 28cd47b
consider order when patching (line numbers), fixed bugs
piameier c9f05da
feat: VariationDiff::computeAllFeatureNames()
pmbittner 8ac9a86
feat: configurations from formula assignments
pmbittner 58acae5
fix: LinkedHashSet for deterministic computeAllFeatureNames
pmbittner 0437b28
basic patching idea
piameier a724fb9
code refactoring
piameier 836d6ab
fixed bugs
piameier dcf2d88
find insert position for ADD and check neigbors for REM
piameier bb766ae
refactoring checkNeighbors method
piameier 6fbdcb5
refactoring findInsertPosition method and formatting code
piameier 0994bae
consider order when patching (line numbers), fixed bugs
piameier a3a02fb
fixed bug
piameier 5fdc441
patch with diff generated from files
piameier 02aa6ba
refactoring, detect alignment problem for ADD nodes, fixed: show subt…
piameier 7cba4bd
changed gitignore
piameier b6e835a
examples add, rem, add-rem, add-alignment, rem-alignment
piameier dbe6ba5
detect alignment problem for REM nodes
piameier c67ea43
example rem-add-alignment
piameier 8a33fb9
fixed bug: alignment problem detection in findInsertPosition()
piameier 39e0483
check for zero variant drift before patching
piameier db7a551
compare patched variant and expected result
piameier cde3999
expected result for example rem-add
piameier 8e81fa7
fixed bug in findInsertPosition
piameier cb25dce
fixed bugs
piameier 5e58efb
added removeNode to recursively drop nodes
piameier e6a5ad6
fixed bug with untouched nodes but with changed parents
piameier 170206d
example nodes-with-2-parents
piameier 86d4c22
moved source code from PatchingExperiment to Patching class
piameier 33efa25
removed unused imports
piameier 3d3fd1c
prepared patching analysis
piameier f31cfbf
improved checkNeighbors with findNearestPositionToIndex()
piameier 7e94413
added context size to check more than one neighbor before and after t…
piameier b48ac2d
fixed bugs
piameier dddff0f
implemented compareAncestors() and fixed bugs
piameier 9da7092
fixed bugs, alternative methods for patching same variants
piameier a7c6672
simplified and fixed bugs
piameier 580a777
fixed bugs for incorrect patched variation trees (new features were m…
piameier aa4c8f0
update patching experiment, possibility to write patch out to file
piameier b1c149e
fixed bugs: rejected insert due to unmodified nodes with two parents …
piameier 4bd5546
fixed bug: FixTrueFalse Formula for deselecting features in view
piameier 77b2d6a
fixed bug in resolve()
piameier ff05f1d
patch variants
piameier 49018ae
refactoring code
piameier 38ac7fe
experiment setup
piameier 76eaa2a
added method arePatchedVariantsEquivalent
piameier 01c2fe4
shell command classes for diff, gnu patch and mpatch
piameier 1d3e9e0
fixed bug in arePatchedVariantsEquivalent
piameier d1237be
modify target patch to fix bug
piameier 10693dd
remove artifact nodes which are children of the root to compare uncha…
piameier 831344f
unchanged relevance predicate
piameier e0adf36
fixed method arePatchedVariantsEquivalent()
piameier c1287d5
fixed method arePatchedVariantsEquivalent()
piameier a798ab8
test equivalence for figure in master thesis
piameier bea648d
adjusted generator and fixed gnupatch and mpatch commands
piameier 386b370
workaround: changed to LF lineendings
piameier 80561b0
fixed bug in EliminateEmptyAlternatives
piameier dd34a35
eliminate empty alternatives after variant configurations
piameier 0c0cbe2
work on generator
piameier f2158a4
refactor generator
piameier 5dc1705
runpatchers in patching experiment
piameier c1a2322
fix from paul for updating labels in EliminateEmptyAlternatives
piameier 0a711fc
work on experiment
piameier 1df8e22
imrpoved performance of Unchanged() slicing criterion
piameier 3ffeb1e
removed sysout in Unchanged()
piameier 93a0841
improved performance of method arePatchedVariantsEquivalent()
piameier 173c77d
fixed bugs in patching
piameier b5110e8
added changes from fixConfigure branch
piameier 4f3a895
added node identifier by presence condition
piameier ec7816d
use view on source patch configured with target for unchanged
piameier 53ec6b5
fixed checkNeighbors2 for patching different variants
piameier 6175510
fixed bug for empty lists in checkNeighbors2
piameier 0793eca
fixed bug for empty lists in checkNeighbors2
piameier 259199a
added experiment with view on patch configured to target variant
piameier 7b0e8bd
fixed bug in isSameList
piameier 6e2a888
store diffs to filesystem if our patching transformator failed
piameier 3a2a14c
store diffs of failed patches (patch transformer) after running all c…
piameier 2e5d5db
fixed bug when removing nodes from a subtree
piameier d9cf4c7
fixed bug in blank lines (unchanged criterion), formatted file
piameier 9f5fba6
write ore files to filesystem to analyze later
piameier c2f2f9b
extended unchanged: compare before and after line, test if node is pr…
piameier beef266
fixed view variants, fixed mpatch
piameier 462f36c
process view variants (gnu, mpatch) afterwards with new files
piameier 1678346
unchanged considering lines before and after
piameier 6ab67a1
patch scenario update
piameier 78f3885
main update
piameier 35a414e
added commit hash to directory name when generating variants
piameier ff61a86
added dataset
piameier 5a95a5b
fixed bugs for commit hash, use release mpatch
piameier f45fffa
removed unsused, not existing imports
piameier bcbc652
write rejected patches of the patch transformer to filesystem
piameier 8e9c386
removed sysout for resultcode
piameier 7b58ccd
removed sysout for resultcode
piameier 773eda2
fixed bugs in unchanged
piameier 4583e7b
fixed bug
piameier e839aae
clear rejected patches map after writing/end batch
piameier a6ddc0c
added counters for unchanged or configure comparison failure
piameier 5c1cfbf
added relevance configure with full configuration
piameier 00118cd
fixed bug
piameier 53a697b
computeAllFeatureNames: changed return type to object
piameier 116fa18
switched to configureWithFullConfig
piameier 2ad7eac
updated patching
piameier 5dc4043
fixed runPatchers method
piameier 65d681b
clean up script for experiment directories
piameier 2f145bd
test cases
piameier 762d476
fixed bug: enforce brackets in updatedLabel
piameier 79d2382
fixed bug: added true and false names to assignment
piameier 174b291
merged
piameier 371bd40
use elimEmptyAlternatives in Generator again, removed constraint for …
piameier 783ec2d
disable logger output
piameier 3bac321
work around for negated features by elim. empty altern.
piameier ae4d808
updated patching experiment
piameier ffe3056
updated generator
piameier 4d75b41
compare with empty lines
piameier ec8f0c2
results busybox
piameier 755c2bd
changed to non static map and elim method
piameier eacb6ab
fixed patching experiment counters
piameier 51d5bde
resetted number of commits per thread
piameier 6555f03
new eval results
piameier 9665928
Merge branch 'VariantSync:main' into main
piameier 996e53d
deleted example files
piameier 5720cc5
README: Note on where to find code of L. Güthing
pmbittner 531b30c
README: bachelor's thesis of Eugen Shulimov
pmbittner 69f46fd
README: section on supported diff algorithms
pmbittner eea15e0
README: update commuting diagram
pmbittner 8eaebed
Update README.md
pmbittner 7f200e8
Update README.md
pmbittner 5b5a4cb
refactor: reuse `VariationNode.assertConsistency` in `DiffNode`
ibbem f65479f
feat: assert that there is at most one ELIF/ELSE
ibbem 7c4366a
feat: assert that the root `DiffNode` is unchanged
ibbem e556df0
feat: `VariationTree.assertConsistency`
ibbem a138e4f
refactor: improve the source tracing mechanism
ibbem bcef3b7
feat: improve the source tracking to reduce `Source.Unknown`
ibbem b55b781
feat: create an interface for and a collection of differs
ibbem 88d6f38
fix: close `ZipFile` in `GitLoader`
ibbem c0f3a4f
doc: fix a typo in `VariationDiffLabelFormat`
ibbem 13561e7
fix(README): path to visual abstract
pmbittner 6da8855
remove unused symlink
pmbittner 1a3b70f
fix: ConfigureSpec vs new Source interface
pmbittner a3c4098
Source::functionExplanation
pmbittner 71340ca
make VariationTree a class instead of a record
pmbittner df60cf1
VariationTree::setSource
pmbittner c001d16
make ViewSource applicable to trees as well
pmbittner 1f09fbc
fix: relevance not treated as source in ViewSource
pmbittner 577d6e1
ViewSource::toString()
pmbittner 8175f2f
use functionExplanation for VDiff/Vtree::toString
pmbittner d6f3684
make BadVDiff be a source
pmbittner ea50301
document TreeView as a source
pmbittner a7c5bbb
rename: VariationTree::root() -> VariationTree::getRoot()
pmbittner e4975db
use functionExplanation in Show titles
pmbittner 7859361
increase version number to 2.4.0
pmbittner 51b97ae
fixed bug in EliminateEmptyAlternatives
piameier 08a4587
fix from paul for updating labels in EliminateEmptyAlternatives
piameier 8e79d24
added changes from fixConfigure branch
piameier d2247c4
Merge branch 'main' into prototyping
piameier 9bc7ae0
clean up
piameier 97433b8
clean up
piameier 2878951
elim empty alternatives
piameier a7b2208
fixed and clean up generator
piameier File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
511 changes: 511 additions & 0 deletions
511
src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java
Large diffs are not rendered by default.
Oops, something went wrong.
40 changes: 40 additions & 0 deletions
40
src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchScenario.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package org.variantsync.diffdetective.experiments.thesis_pm; | ||
|
|
||
| import org.variantsync.diffdetective.variation.DiffLinesLabel; | ||
| import org.variantsync.diffdetective.variation.Label; | ||
| import org.variantsync.diffdetective.variation.diff.Time; | ||
| import org.variantsync.diffdetective.variation.diff.VariationDiff; | ||
| import org.variantsync.diffdetective.variation.diff.view.DiffView; | ||
| import org.variantsync.diffdetective.variation.tree.VariationTree; | ||
| import org.variantsync.diffdetective.variation.tree.view.TreeView; | ||
| import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; | ||
| import org.variantsync.diffdetective.variation.tree.view.relevance.ConfigureWithFullConfig; | ||
| import org.variantsync.diffdetective.variation.tree.view.relevance.Unchanged; | ||
|
|
||
| public class PatchScenario<L extends Label> { | ||
| public VariationDiff<L> sourcePatch; | ||
| public VariationTree<L> targetVariantBefore; | ||
| public VariationDiff<L> patchGroundTruth; | ||
| public VariationTree<L> patchedVariantGroundTruth; | ||
| public ConfigureWithFullConfig sourceVariantConfig; | ||
| public ConfigureWithFullConfig targetVariantConfig; | ||
| public VariationTree<DiffLinesLabel> sourceVariantAfterRedToCrossVarFeatures; | ||
| public Unchanged unchangedAfter; | ||
| public VariationTree<DiffLinesLabel> targetVariantBeforeRedToUnchanged; | ||
|
|
||
| public PatchScenario(VariationDiff<L> sourcePatch, | ||
| VariationTree<L> targetVariantBefore, VariationDiff<L> patchGroundTruth, | ||
| VariationTree<L> patchedVariantGroundTruth, ConfigureWithFullConfig sourceVariantConfig, ConfigureWithFullConfig targetVariantConfig) { | ||
| this.sourcePatch = sourcePatch; | ||
| this.targetVariantBefore = targetVariantBefore; | ||
| this.patchGroundTruth = patchGroundTruth; | ||
| this.patchedVariantGroundTruth = patchedVariantGroundTruth; | ||
| this.sourceVariantConfig = sourceVariantConfig; | ||
| this.targetVariantConfig = targetVariantConfig; | ||
| this.sourceVariantAfterRedToCrossVarFeatures = (VariationTree<DiffLinesLabel>) TreeView.tree(sourcePatch.project(Time.AFTER), this.targetVariantConfig); | ||
| VariationDiff<DiffLinesLabel> sourcePatchConfiguredToCrossVarFeatures = (VariationDiff<DiffLinesLabel>) DiffView.optimized(sourcePatch, targetVariantConfig); | ||
| this.unchangedAfter = new Unchanged((VariationDiff<DiffLinesLabel>) sourcePatchConfiguredToCrossVarFeatures, Time.AFTER); | ||
| Unchanged unchangedBefore = new Unchanged((VariationDiff<DiffLinesLabel>) sourcePatchConfiguredToCrossVarFeatures, Time.BEFORE); | ||
| this.targetVariantBeforeRedToUnchanged = (VariationTree<DiffLinesLabel>) TreeView.tree(this.targetVariantBefore, unchangedBefore); | ||
| } | ||
| } |
597 changes: 597 additions & 0 deletions
597
src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java
Large diffs are not rendered by default.
Oops, something went wrong.
55 changes: 55 additions & 0 deletions
55
src/main/java/org/variantsync/diffdetective/shell/DiffCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package org.variantsync.diffdetective.shell; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| /** Single executable command with arguments. */ | ||
| public class DiffCommand extends ShellCommand { | ||
| private final String[] parts; | ||
| private boolean filesDifferent; | ||
|
|
||
| /** | ||
| * Constructs a single command. | ||
| * The first argument has to be a path to an executable which will be given all of the | ||
| * remaining arguments as parameters on execution. | ||
| * | ||
| * @param cmd executable path and arguments for the executable | ||
| */ | ||
| public DiffCommand(final String... cmd) { | ||
| parts = cmd; | ||
| } | ||
|
|
||
| @Override | ||
| public String[] parts() { | ||
| return parts; | ||
| } | ||
|
|
||
| /** | ||
| * Interpret the result/exit code returned from a shell command. | ||
| * An {@code ShellException} is thrown if the result code is an error. | ||
| * | ||
| * @param resultCode the code that is to be parsed | ||
| * @param output the output of the shell command | ||
| * @return the output of the shell command | ||
| * @throws ShellException if {@code resultCode} is an error | ||
| */ | ||
| @Override | ||
| public List<String> interpretResult(int resultCode, List<String> output) throws ShellException { | ||
| // inputs are the same | ||
| if (resultCode == 0) { | ||
| filesDifferent = false; | ||
| return output; | ||
| } | ||
| // if inputs are different | ||
| if (resultCode == 1) { | ||
| filesDifferent = true; | ||
| return output; | ||
| } | ||
| // everything else: "serious trouble": exit code 2 | ||
| throw new ShellException(output); | ||
|
|
||
| } | ||
|
|
||
| public boolean areFilesDifferent() { | ||
| return filesDifferent; | ||
| } | ||
| } |
55 changes: 55 additions & 0 deletions
55
src/main/java/org/variantsync/diffdetective/shell/GnuPatchCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package org.variantsync.diffdetective.shell; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| /** Single executable command with arguments. */ | ||
| public class GnuPatchCommand extends ShellCommand { | ||
| private final String[] parts; | ||
| private boolean patchingSuccessful; | ||
|
|
||
| /** | ||
| * Constructs a single command. | ||
| * The first argument has to be a path to an executable which will be given all of the | ||
| * remaining arguments as parameters on execution. | ||
| * | ||
| * @param cmd executable path and arguments for the executable | ||
| */ | ||
| public GnuPatchCommand(final String... cmd) { | ||
| parts = cmd; | ||
| } | ||
|
|
||
| @Override | ||
| public String[] parts() { | ||
| return parts; | ||
| } | ||
|
|
||
| /** | ||
| * Interpret the result/exit code returned from a shell command. | ||
| * An {@code ShellException} is thrown if the result code is an error. | ||
| * | ||
| * @param resultCode the code that is to be parsed | ||
| * @param output the output of the shell command | ||
| * @return the output of the shell command | ||
| * @throws ShellException if {@code resultCode} is an error | ||
| */ | ||
| @Override | ||
| public List<String> interpretResult(int resultCode, List<String> output) throws ShellException { | ||
| // patching was successful | ||
| if (resultCode == 0) { | ||
| patchingSuccessful = true; | ||
| return null; | ||
| } | ||
| // some hunks cannot be applied or merge conflicts | ||
| if (resultCode == 1) { | ||
| patchingSuccessful = false; | ||
| return null; | ||
| } | ||
| // everything else: "serious trouble": exit code 2 | ||
| throw new ShellException(output); | ||
|
|
||
| } | ||
|
|
||
| public boolean isPatchingSuccessful() { | ||
| return patchingSuccessful; | ||
| } | ||
| } |
55 changes: 55 additions & 0 deletions
55
src/main/java/org/variantsync/diffdetective/shell/MPatchCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package org.variantsync.diffdetective.shell; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| /** Single executable command with arguments. */ | ||
| public class MPatchCommand extends ShellCommand { | ||
| private final String[] parts; | ||
| private boolean patchingSuccessful; | ||
|
|
||
| /** | ||
| * Constructs a single command. | ||
| * The first argument has to be a path to an executable which will be given all of the | ||
| * remaining arguments as parameters on execution. | ||
| * | ||
| * @param cmd executable path and arguments for the executable | ||
| */ | ||
| public MPatchCommand(final String... cmd) { | ||
| parts = cmd; | ||
| } | ||
|
|
||
| @Override | ||
| public String[] parts() { | ||
| return parts; | ||
| } | ||
|
|
||
| /** | ||
| * Interpret the result/exit code returned from a shell command. | ||
| * An {@code ShellException} is thrown if the result code is an error. | ||
| * | ||
| * @param resultCode the code that is to be parsed | ||
| * @param output the output of the shell command | ||
| * @return the output of the shell command | ||
| * @throws ShellException if {@code resultCode} is an error | ||
| */ | ||
| @Override | ||
| public List<String> interpretResult(int resultCode, List<String> output) throws ShellException { | ||
| // patching was successful ??? | ||
| if (resultCode == 0) { | ||
| patchingSuccessful = true; | ||
| return null; | ||
| } | ||
| // some hunks cannot be applied or merge conflicts ??? | ||
| if (resultCode == 1) { | ||
| patchingSuccessful = false; | ||
| return null; | ||
| } | ||
| // everything else: "serious trouble": exit code 2 ??? | ||
| throw new ShellException(output); | ||
|
|
||
| } | ||
|
|
||
| public boolean isPatchingSuccessful() { | ||
| return patchingSuccessful; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -378,16 +378,16 @@ public int count(final Predicate<DiffNode<L>> nodesToCount) { | |
| * This method is deterministic: It will return the feature names always in the same order, assuming the variation diff is not changed inbetween. | ||
| * @return A set of every occuring feature name. | ||
| */ | ||
| public LinkedHashSet<String> computeAllFeatureNames() { | ||
| LinkedHashSet<String> features = new LinkedHashSet<>(); | ||
| public LinkedHashSet<Object> computeAllFeatureNames() { | ||
| LinkedHashSet<Object> features = new LinkedHashSet<>(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was it necessary to turn these strings into objects, only to recover that lost information by casting a few lines later? |
||
| forAll(node -> { | ||
| if (node.isConditionalAnnotation()) { | ||
| features.addAll(node.getFormula().getUniqueContainedFeatures()); | ||
| } | ||
| }); | ||
| // Since FeatureIDE falsely reports constants "True" and "False" as feature names, we have to remove them from the resulting set. | ||
| features.removeIf(FixTrueFalse::isTrueLiteral); | ||
| features.removeIf(FixTrueFalse::isFalseLiteral); | ||
| features.removeIf(f -> FixTrueFalse.isTrueLiteral((String) f)); | ||
| features.removeIf(f -> FixTrueFalse.isFalseLiteral((String) f)); | ||
| return features; | ||
| } | ||
|
|
||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this change is sensible. I do not remember why we chose CRLF here in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the comment states, we introduced
LINEBREAKinstead of usingSystem.lineSeparatorto ensure that the line endings of our outputs are independent of the operating system. In particular, if I remember correctly, there was an issue with some dependency (something line graph related according to the Git history) that caused issues on Windows. As windows applications typically take issue with parsing text files without carriage returns while Linux applications just treat the carriage return as data, we use '\r\n' for all outputs.In summary, the biggest potential issue is probably Windows compatibility. As the output of DiffDetective will not match the expectations in that environment. However, I think we don't use this constant very consistently anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the detailed analysis. If I remember correctly, some tests that read/write files failed on Windows but not Linux. 🤔
Maybe it is safest to just leave LINEBREAK as is, and maybe add a second constant
LINEBREAK_LFfor code parts of @piameier.