• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

HicServices / RDMP / 6245535001

20 Sep 2023 07:44AM UTC coverage: 57.013%. First build
6245535001

push

github

web-flow
8.1.0 Release (#1628)

* Bump Newtonsoft.Json from 13.0.1 to 13.0.2

Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 13.0.1 to 13.0.2.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/13.0.1...13.0.2)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump NLog from 5.0.5 to 5.1.0

Bumps [NLog](https://github.com/NLog/NLog) from 5.0.5 to 5.1.0.
- [Release notes](https://github.com/NLog/NLog/releases)
- [Changelog](https://github.com/NLog/NLog/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/NLog/NLog/compare/v5.0.5...v5.1.0)

---
updated-dependencies:
- dependency-name: NLog
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump NLog from 5.0.5 to 5.1.0

* Fix -r flag - should have been --results-directory all along

* Bump Newtonsoft.Json from 13.0.1 to 13.0.2

* Bump YamlDotNet from 12.0.2 to 12.1.0

Bumps [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 12.0.2 to 12.1.0.
- [Release notes](https://github.com/aaubry/YamlDotNet/releases)
- [Commits](https://github.com/aaubry/YamlDotNet/compare/v12.0.2...v12.1.0)

---
updated-dependencies:
- dependency-name: YamlDotNet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump Moq from 4.18.2 to 4.18.3

Bumps [Moq](https://github.com/moq/moq4) from 4.18.2 to 4.18.3.
- [Release notes](https://github.com/moq/moq4/releases)
- [Changelog](https://github.com/moq/moq4/blob/main/CHANGELOG.md)
- [Commits](https://github.com/moq/moq4/compare/v4.18.2...v4.18.3)

---
updated-dependencies:
- dependency-name: Moq
... (continued)

10732 of 20257 branches covered (0.0%)

Branch coverage included in aggregate %.

48141 of 48141 new or added lines in 1086 files covered. (100.0%)

30685 of 52388 relevant lines covered (58.57%)

7387.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.46
/Rdmp.Core/ReusableLibraryCode/Diff.cs
1
// Copyright (c) The University of Dundee 2018-2019
2
// This file is part of the Research Data Management Platform (RDMP).
3
// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
4
// RDMP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
5
// You should have received a copy of the GNU General Public License along with RDMP. If not, see <https://www.gnu.org/licenses/>.
6

7
using System;
8
using System.Collections;
9
using System.Text.RegularExpressions;
10

11
namespace Rdmp.Core.ReusableLibraryCode;
12

13
/// <summary>
14
/// This Class implements the Difference Algorithm published in
15
/// "An O(ND) Difference Algorithm and its Variations" by Eugene Myers
16
/// Algorithmica Vol. 1 No. 2, 1986, p 251.
17
/// 
18
/// <para>There are many C, Java, Lisp implementations public available but they all seem to come
19
/// from the same source (diffutils) that is under the (unfree) GNU public License
20
/// and cannot be reused as a sourcecode for a commercial application.
21
/// There are very old C implementations that use other (worse) algorithms.
22
/// Microsoft also published sourcecode of a diff-tool (windiff) that uses some tree data.
23
/// Also, a direct transfer from a C source to C# is not easy because there is a lot of pointer
24
/// arithmetic in the typical C solutions and i need a managed solution.
25
/// These are the reasons why I implemented the original published algorithm from the scratch and
26
/// make it available without the GNU license limitations.
27
/// I do not need a high performance diff tool because it is used only sometimes.
28
/// I will do some performance tweaking when needed.</para>
29
/// 
30
/// <para>The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
31
/// each line is converted into a (hash) number. See DiffText(). </para>
32
/// 
33
/// <para>Some changes to the original algorithm:
34
/// The original algorithm was described using a recursive approach and comparing zero indexed arrays.
35
/// Extracting sub-arrays and rejoining them is very performance and memory intensive so the same
36
/// (readonly) data arrays are passed around together with their lower and upper bounds.
37
/// This circumstance makes the LCS and SMS functions more complicate.
38
/// I added some code to the LCS function to get a fast response on sub-arrays that are identical,
39
/// completely deleted or inserted.</para>
40
/// 
41
/// <para>The result from a comparison is stored in 2 arrays that flag for modified (deleted or inserted)
42
/// lines in the 2 data arrays. These bits are then analysed to produce a array of Item objects.</para>
43
/// 
44
/// <para>Further possible optimizations:
45
/// (first rule: don't do it; second: don't do it yet)
46
/// The arrays DataA and DataB are passed as parameters, but are never changed after the creation
47
/// so they can be members of the class to avoid the parameter overhead.
48
/// In SMS is a lot of boundary arithmetic in the for-D and for-k loops that can be done by increment
49
/// and decrement of local variables.
50
/// The DownVector and UpVector arrays are always created and destroyed each time the SMS gets called.
51
/// It is possible to reuse them when transferring them to members of the class.</para>
52
/// 
53
/// <para>diff.cs: A port of the algorithm to C#
54
/// Created by Matthias Hertel, see http://www.mathertel.de
55
/// This work is licensed under a Creative Commons Attribution 2.0 Germany License.
56
/// see http://creativecommons.org/licenses/by/2.0/de/</para>
57
/// 
58
/// <para>Changes:
59
/// 2002.09.20 There was a "hang" in some situations.
60
/// Now I understand a little bit more of the SMS algorithm.
61
/// There have been overlapping boxes; that where analyzed partial differently.
62
/// One return-point is enough.
63
/// A assertion was added in CreateDiffs when in debug-mode, that counts the number of equal (no modified) lines in both arrays.
64
/// They must be identical.</para>
65
/// 
66
/// <para>2003.02.07 Out of bounds error in the Up/Down vector arrays in some situations.
67
/// The two vectors are now accessed using different offsets that are adjusted using the start k-Line.
68
/// A test case is added. </para>
69
/// 
70
/// <para>2006.03.05 Some documentation and a direct Diff entry point.</para>
71
/// 
72
/// <para>2006.03.08 Refactored the API to static methods on the Diff class to make usage simpler.
73
/// 2006.03.10 using the standard Debug class for self-test now.
74
///            compile with: csc /target:exe /out:diffTest.exe /d:DEBUG /d:TRACE /d:SELFTEST Diff.cs</para>
75
/// </summary>
76
public class Diff
77
{
78
    /// <summary>details of one difference.</summary>
79
    public struct Item
80
    {
81
        /// <summary>Start Line number in Data A.</summary>
82
        public int StartA;
83

84
        /// <summary>Start Line number in Data B.</summary>
85
        public int StartB;
86

87
        /// <summary>Number of changes in Data A.</summary>
88
        public int deletedA;
89

90
        /// <summary>Number of changes in Data A.</summary>
91
        public int insertedB;
92
    } // Item
93

94
    /// <summary>
95
    /// Shortest Middle Snake Return Data
96
    /// </summary>
97
    private struct SMSRD
98
    {
99
        internal int x, y;
100
        // internal int u, v;  // 2002.09.20: no need for 2 points
101
    }
102

103

104
    #region self-Test
105

106
#if (SELFTEST)
107
    /// <summary>
108
    /// start a self- / box-test for some diff cases and report to the debug output.
109
    /// </summary>
110
    /// <param name="args">not used</param>
111
    /// <returns>always 0</returns>
112
    public static int Main(string[] args) {
113
      StringBuilder ret = new StringBuilder();
114
      string a, b;
115

116
      System.Diagnostics.ConsoleTraceListener ctl = new System.Diagnostics.ConsoleTraceListener(false);
117
      System.Diagnostics.Debug.Listeners.Add(ctl);
118

119
      System.Console.WriteLine("Diff Self Test...");
120

121
      // test all changes
122
      a = "a,b,c,d,e,f,g,h,i,j,k,l".Replace(',', '\n');
123
      b = "0,1,2,3,4,5,6,7,8,9".Replace(',', '\n');
124
      System.Diagnostics.Debug.Assert(TestHelper(Diff.DiffText(a, b, false, false, false))
125
        == "12.10.0.0*",
126
        "all-changes test failed.");
127
      System.Diagnostics.Debug.WriteLine("all-changes test passed.");
128
      // test all same
129
      a = "a,b,c,d,e,f,g,h,i,j,k,l".Replace(',', '\n');
130
      b = a;
131
      System.Diagnostics.Debug.Assert(TestHelper(Diff.DiffText(a, b, false, false, false))
132
        == "",
133
        "all-same test failed.");
134
      System.Diagnostics.Debug.WriteLine("all-same test passed.");
135

136
      // test snake
137
      a = "a,b,c,d,e,f".Replace(',', '\n');
138
      b = "b,c,d,e,f,x".Replace(',', '\n');
139
      System.Diagnostics.Debug.Assert(TestHelper(Diff.DiffText(a, b, false, false, false))
140
        == "1.0.0.0*0.1.6.5*",
141
        "snake test failed.");
142
      System.Diagnostics.Debug.WriteLine("snake test passed.");
143

144
      // 2002.09.20 - repro
145
      a = "c1,a,c2,b,c,d,e,g,h,i,j,c3,k,l".Replace(',', '\n');
146
      b = "C1,a,C2,b,c,d,e,I1,e,g,h,i,j,C3,k,I2,l".Replace(',', '\n');
147
      System.Diagnostics.Debug.Assert(TestHelper(Diff.DiffText(a, b, false, false, false))
148
        == "1.1.0.0*1.1.2.2*0.2.7.7*1.1.11.13*0.1.13.15*",
149
        "repro20020920 test failed.");
150
      System.Diagnostics.Debug.WriteLine("repro20020920 test passed.");
151

152
      // 2003.02.07 - repro
153
      a = "F".Replace(',', '\n');
154
      b = "0,F,1,2,3,4,5,6,7".Replace(',', '\n');
155
      System.Diagnostics.Debug.Assert(TestHelper(Diff.DiffText(a, b, false, false, false))
156
        == "0.1.0.0*0.7.1.2*",
157
        "repro20030207 test failed.");
158
      System.Diagnostics.Debug.WriteLine("repro20030207 test passed.");
159

160
      // Muegel - repro
161
      a = "HELLO\nWORLD";
162
      b = "\n\nhello\n\n\n\nworld\n";
163
      System.Diagnostics.Debug.Assert(TestHelper(Diff.DiffText(a, b, false, false, false))
164
        == "2.8.0.0*",
165
        "repro20030409 test failed.");
166
      System.Diagnostics.Debug.WriteLine("repro20030409 test passed.");
167

168
    // test some differences
169
      a = "a,b,-,c,d,e,f,f".Replace(',', '\n');
170
      b = "a,b,x,c,e,f".Replace(',', '\n');
171
      System.Diagnostics.Debug.Assert(TestHelper(Diff.DiffText(a, b, false, false, false))
172
        == "1.1.2.2*1.0.4.4*1.0.6.5*",
173
        "some-changes test failed.");
174
      System.Diagnostics.Debug.WriteLine("some-changes test passed.");
175

176
      System.Diagnostics.Debug.WriteLine("End.");
177
      System.Diagnostics.Debug.Flush();
178

179
      return (0);
180
    }
181

182

183
    public static string TestHelper(Item []f) {
184
      StringBuilder ret = new StringBuilder();
185
      for (int n = 0; n < f.Length; n++) {
186
        ret.Append(f[n].deletedA.ToString() + "." + f[n].insertedB.ToString() + "." + f[n].StartA.ToString() + "." + f[n].StartB.ToString() + "*");
187
      }
188
      // Debug.Write(5, "TestHelper", ret.ToString());
189
      return (ret.ToString());
190
    }
191
#endif
192

193
    #endregion
194

195

196
    /// <summary>
197
    /// Find the difference in 2 texts, comparing by textlines.
198
    /// </summary>
199
    /// <param name="TextA">A-version of the text (usually the old one)</param>
200
    /// <param name="TextB">B-version of the text (usually the new one)</param>
201
    /// <returns>Returns a array of Items that describe the differences.</returns>
202
    public static Item[] DiffText(string TextA, string TextB) =>
203
        DiffText(TextA, TextB, false, false, false); // DiffText
2✔
204

205

206
    /// <summary>
207
    /// Find the difference in 2 text documents, comparing by textlines.
208
    /// The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
209
    /// each line is converted into a (hash) number. This hash-value is computed by storing all
210
    /// textlines into a common hashtable so i can find duplicates in there, and generating a
211
    /// new number each time a new textline is inserted.
212
    /// </summary>
213
    /// <param name="TextA">A-version of the text (usually the old one)</param>
214
    /// <param name="TextB">B-version of the text (usually the new one)</param>
215
    /// <param name="trimSpace">When set to true, all leading and trailing whitespace characters are stripped out before the comparison is done.</param>
216
    /// <param name="ignoreSpace">When set to true, all whitespace characters are converted to a single space character before the comparison is done.</param>
217
    /// <param name="ignoreCase">When set to true, all characters are converted to their lowercase equivalents before the comparison is done.</param>
218
    /// <returns>Returns a array of Items that describe the differences.</returns>
219
    public static Item[] DiffText(string TextA, string TextB, bool trimSpace, bool ignoreSpace, bool ignoreCase)
220
    {
221
        // prepare the input-text and convert to comparable numbers.
222
        var h = new Hashtable(TextA.Length + TextB.Length);
2✔
223

224
        // The A-Version of the data (original data) to be compared.
225
        var DataA = new DiffData(DiffCodes(TextA, h, trimSpace, ignoreSpace, ignoreCase));
2✔
226

227
        // The B-Version of the data (modified data) to be compared.
228
        var DataB = new DiffData(DiffCodes(TextB, h, trimSpace, ignoreSpace, ignoreCase));
2✔
229

230
        LCS(DataA, 0, DataA.Length, DataB, 0, DataB.Length);
2✔
231
        return CreateDiffs(DataA, DataB);
2✔
232
    } // DiffText
233

234

235
    /// <summary>
236
    /// Find the difference in 2 arrays of integers.
237
    /// </summary>
238
    /// <param name="ArrayA">A-version of the numbers (usually the old one)</param>
239
    /// <param name="ArrayB">B-version of the numbers (usually the new one)</param>
240
    /// <returns>Returns a array of Items that describe the differences.</returns>
241
    public static Item[] DiffInt(int[] ArrayA, int[] ArrayB)
242
    {
243
        // The A-Version of the data (original data) to be compared.
244
        var DataA = new DiffData(ArrayA);
×
245

246
        // The B-Version of the data (modified data) to be compared.
247
        var DataB = new DiffData(ArrayB);
×
248

249
        LCS(DataA, 0, DataA.Length, DataB, 0, DataB.Length);
×
250
        return CreateDiffs(DataA, DataB);
×
251
    } // Diff
252

253

254
    /// <summary>
255
    /// This function converts all textlines of the text into unique numbers for every unique textline
256
    /// so further work can work only with simple numbers.
257
    /// </summary>
258
    /// <param name="aText">the input text</param>
259
    /// <param name="h">This extern initialized hashtable is used for storing all ever used textlines.</param>
260
    /// <param name="trimSpace">ignore leading and trailing space characters</param>
261
    /// <param name="ignoreSpace">ignore whitespace differences e.g. double spaces vs single spaces</param>
262
    /// <param name="ignoreCase">ignore capitalisation in comparison</param>
263
    /// <returns>a array of integers.</returns>
264
    private static int[] DiffCodes(string aText, Hashtable h, bool trimSpace, bool ignoreSpace, bool ignoreCase)
265
    {
266
        // get all codes of the text
267
        var lastUsedCode = h.Count;
4✔
268

269
        // strip off all cr, only use lf as line separator.
270
        aText = aText.Replace("\r", "");
4✔
271
        var Lines = aText.Split('\n');
4✔
272

273
        var Codes = new int[Lines.Length];
4✔
274

275
        for (var i = 0; i < Lines.Length; ++i)
16✔
276
        {
277
            var s = Lines[i];
4✔
278
            if (trimSpace)
4!
279
                s = s.Trim();
×
280

281
            if (ignoreSpace) s = Regex.Replace(s, "\\s+", " ");
4!
282

283
            if (ignoreCase)
4!
284
                s = s.ToLower();
×
285

286
            var aCode = h[s];
4✔
287
            if (aCode == null)
4!
288
            {
289
                lastUsedCode++;
4✔
290
                h[s] = lastUsedCode;
4✔
291
                Codes[i] = lastUsedCode;
4✔
292
            }
293
            else
294
            {
295
                Codes[i] = (int)aCode;
×
296
            } // if
297
        } // for
298

299
        return Codes;
4✔
300
    } // DiffCodes
301

302

303
    /// <summary>
304
    /// This is the algorithm to find the Shortest Middle Snake (SMS).
305
    /// </summary>
306
    /// <param name="DataA">sequence A</param>
307
    /// <param name="LowerA">lower bound of the actual range in DataA</param>
308
    /// <param name="UpperA">upper bound of the actual range in DataA (exclusive)</param>
309
    /// <param name="DataB">sequence B</param>
310
    /// <param name="LowerB">lower bound of the actual range in DataB</param>
311
    /// <param name="UpperB">upper bound of the actual range in DataB (exclusive)</param>
312
    /// <returns>a MiddleSnakeData record containing x,y and u,v</returns>
313
    private static SMSRD SMS(DiffData DataA, int LowerA, int UpperA, DiffData DataB, int LowerB, int UpperB)
314
    {
315
        var MAX = DataA.Length + DataB.Length + 1;
2✔
316

317
        var DownK = LowerA - LowerB; // the k-line to start the forward search
2✔
318
        var UpK = UpperA - UpperB; // the k-line to start the reverse search
2✔
319

320
        var Delta = UpperA - LowerA - (UpperB - LowerB);
2✔
321
        var oddDelta = (Delta & 1) != 0;
2✔
322

323
        // vector for the (0,0) to (x,y) search
324
        var DownVector = new int[2 * MAX + 2];
2✔
325

326
        // vector for the (u,v) to (N,M) search
327
        var UpVector = new int[2 * MAX + 2];
2✔
328

329
        // The vectors in the publication accepts negative indexes. the vectors implemented here are 0-based
330
        // and are access using a specific offset: UpOffset UpVector and DownOffset for DownVektor
331
        var DownOffset = MAX - DownK;
2✔
332
        var UpOffset = MAX - UpK;
2✔
333

334
        var MaxD = (UpperA - LowerA + UpperB - LowerB) / 2 + 1;
2✔
335

336
        // Debug.Write(2, "SMS", String.Format("Search the box: A[{0}-{1}] to B[{2}-{3}]", LowerA, UpperA, LowerB, UpperB));
337

338
        // init vectors
339
        DownVector[DownOffset + DownK + 1] = LowerA;
2✔
340
        UpVector[UpOffset + UpK - 1] = UpperA;
2✔
341

342
        for (var D = 0; D <= MaxD; D++)
8!
343
        {
344
            // Extend the forward path.
345
            SMSRD ret;
346
            for (var k = DownK - D; k <= DownK + D; k += 2)
20✔
347
            {
348
                // Debug.Write(0, "SMS", "extend forward path " + k.ToString());
349

350
                // find the only or better starting point
351
                int x;
352
                if (k == DownK - D)
6✔
353
                {
354
                    x = DownVector[DownOffset + k + 1]; // down
4✔
355
                }
356
                else
357
                {
358
                    x = DownVector[DownOffset + k - 1] + 1; // a step to the right
2✔
359
                    if (k < DownK + D && DownVector[DownOffset + k + 1] >= x)
2!
360
                        x = DownVector[DownOffset + k + 1]; // down
×
361
                }
362

363
                var y = x - k;
6✔
364

365
                // find the end of the furthest reaching forward D-path in diagonal k.
366
                while (x < UpperA && y < UpperB && DataA.data[x] == DataB.data[y])
6!
367
                {
368
                    x++;
×
369
                    y++;
×
370
                }
371

372
                DownVector[DownOffset + k] = x;
6✔
373

374
                // overlap ?
375
                if (oddDelta && UpK - D < k && k < UpK + D)
6!
376
                    if (UpVector[UpOffset + k] <= DownVector[DownOffset + k])
×
377
                    {
378
                        ret.x = DownVector[DownOffset + k];
×
379
                        ret.y = DownVector[DownOffset + k] - k;
×
380
                        // ret.u = UpVector[UpOffset + k];      // 2002.09.20: no need for 2 points
381
                        // ret.v = UpVector[UpOffset + k] - k;
382
                        return ret;
×
383
                    } // if
384
                // if
385
            } // for k
386

387
            // Extend the reverse path.
388
            for (var k = UpK - D; k <= UpK + D; k += 2)
12✔
389
            {
390
                // Debug.Write(0, "SMS", "extend reverse path " + k.ToString());
391

392
                // find the only or better starting point
393
                int x;
394
                if (k == UpK + D)
4✔
395
                {
396
                    x = UpVector[UpOffset + k - 1]; // up
2✔
397
                }
398
                else
399
                {
400
                    x = UpVector[UpOffset + k + 1] - 1; // left
2✔
401
                    if (k > UpK - D && UpVector[UpOffset + k - 1] < x)
2!
402
                        x = UpVector[UpOffset + k - 1]; // up
×
403
                } // if
404

405
                var y = x - k;
4✔
406

407
                while (x > LowerA && y > LowerB && DataA.data[x - 1] == DataB.data[y - 1])
4!
408
                {
409
                    x--;
×
410
                    y--; // diagonal
×
411
                }
412

413
                UpVector[UpOffset + k] = x;
4✔
414

415
                // overlap ?
416
                if (!oddDelta && DownK - D <= k && k <= DownK + D)
4✔
417
                    if (UpVector[UpOffset + k] <= DownVector[DownOffset + k])
4✔
418
                    {
419
                        ret.x = DownVector[DownOffset + k];
2✔
420
                        ret.y = DownVector[DownOffset + k] - k;
2✔
421
                        // ret.u = UpVector[UpOffset + k];     // 2002.09.20: no need for 2 points
422
                        // ret.v = UpVector[UpOffset + k] - k;
423
                        return ret;
2✔
424
                    } // if
425
                // if
426
            } // for k
427
        } // for D
428

429
        throw new ApplicationException("the algorithm should never come here.");
×
430
    } // SMS
431

432

433
    /// <summary>
434
    /// This is the divide-and-conquer implementation of the longes common-subsequence (LCS)
435
    /// algorithm.
436
    /// The published algorithm passes recursively parts of the A and B sequences.
437
    /// To avoid copying these arrays the lower and upper bounds are passed while the sequences stay constant.
438
    /// </summary>
439
    /// <param name="DataA">sequence A</param>
440
    /// <param name="LowerA">lower bound of the actual range in DataA</param>
441
    /// <param name="UpperA">upper bound of the actual range in DataA (exclusive)</param>
442
    /// <param name="DataB">sequence B</param>
443
    /// <param name="LowerB">lower bound of the actual range in DataB</param>
444
    /// <param name="UpperB">upper bound of the actual range in DataB (exclusive)</param>
445
    private static void LCS(DiffData DataA, int LowerA, int UpperA, DiffData DataB, int LowerB, int UpperB)
446
    {
447
        // Debug.Write(2, "LCS", String.Format("Analyse the box: A[{0}-{1}] to B[{2}-{3}]", LowerA, UpperA, LowerB, UpperB));
448

449
        // Fast walkthrough equal lines at the start
450
        while (LowerA < UpperA && LowerB < UpperB && DataA.data[LowerA] == DataB.data[LowerB])
6!
451
        {
452
            LowerA++;
×
453
            LowerB++;
×
454
        }
455

456
        // Fast walkthrough equal lines at the end
457
        while (LowerA < UpperA && LowerB < UpperB && DataA.data[UpperA - 1] == DataB.data[UpperB - 1])
6!
458
        {
459
            --UpperA;
×
460
            --UpperB;
×
461
        }
462

463
        if (LowerA == UpperA)
6✔
464
        {
465
            // mark as inserted lines.
466
            while (LowerB < UpperB)
4✔
467
                DataB.modified[LowerB++] = true;
2✔
468
        }
469
        else if (LowerB == UpperB)
4✔
470
        {
471
            // mark as deleted lines.
472
            while (LowerA < UpperA)
4✔
473
                DataA.modified[LowerA++] = true;
2✔
474
        }
475
        else
476
        {
477
            // Find the middle snakea and length of an optimal path for A and B
478
            var smsrd = SMS(DataA, LowerA, UpperA, DataB, LowerB, UpperB);
2✔
479
            // Debug.Write(2, "MiddleSnakeData", String.Format("{0},{1}", smsrd.x, smsrd.y));
480

481
            // The path is from LowerX to (x,y) and (x,y) ot UpperX
482
            LCS(DataA, LowerA, smsrd.x, DataB, LowerB, smsrd.y);
2✔
483
            LCS(DataA, smsrd.x, UpperA, DataB, smsrd.y, UpperB); // 2002.09.20: no need for 2 points
2✔
484
        }
485
    } // LCS()
2✔
486

487

488
    /// <summary>Scan the tables of which lines are inserted and deleted,
489
    /// producing an edit script in forward order.
490
    /// </summary>
491
    /// dynamic array
492
    private static Item[] CreateDiffs(DiffData DataA, DiffData DataB)
493
    {
494
        var a = new ArrayList();
2✔
495

496
        int StartA, StartB;
497

498
        var LineA = 0;
2✔
499
        var LineB = 0;
2✔
500
        while (LineA < DataA.Length || LineB < DataB.Length)
4✔
501
            if (LineA < DataA.Length && !DataA.modified[LineA]
2!
502
                                     && LineB < DataB.Length && !DataB.modified[LineB])
2✔
503
            {
504
                // equal lines
505
                LineA++;
×
506
                LineB++;
×
507
            }
508
            else
509
            {
510
                // maybe deleted and/or inserted lines
511
                StartA = LineA;
2✔
512
                StartB = LineB;
2✔
513

514
                while (LineA < DataA.Length && (LineB >= DataB.Length || DataA.modified[LineA]))
4✔
515
                    // while (LineA < DataA.Length && DataA.modified[LineA])
516
                    LineA++;
2✔
517

518
                while (LineB < DataB.Length && (LineA >= DataA.Length || DataB.modified[LineB]))
4!
519
                    // while (LineB < DataB.Length && DataB.modified[LineB])
520
                    LineB++;
2✔
521

522
                if (StartA < LineA || StartB < LineB)
2!
523
                    // store a new difference-item
524
                    a.Add(new Item
2✔
525
                    {
2✔
526
                        StartA = StartA,
2✔
527
                        StartB = StartB,
2✔
528
                        deletedA = LineA - StartA,
2✔
529
                        insertedB = LineB - StartB
2✔
530
                    }); // if
2✔
531
            } // if
532

533
        // while
534
        var result = new Item[a.Count];
2✔
535
        a.CopyTo(result);
2✔
536

537
        return result;
2✔
538
    }
539
} // class Diff
540

541
/// <summary>Data on one input file being compared.
542
/// </summary>
543
internal class DiffData
544
{
545
    /// <summary>Number of elements (lines).</summary>
546
    internal int Length;
547

548
    /// <summary>Buffer of numbers that will be compared.</summary>
549
    internal int[] data;
550

551
    /// <summary>
552
    /// Array of booleans that flag for modified data.
553
    /// This is the result of the diff.
554
    /// This means deletedA in the first Data or inserted in the second Data.
555
    /// </summary>
556
    internal bool[] modified;
557

558
    /// <summary>
559
    /// Initialize the Diff-Data buffer.
560
    /// </summary>
561
    /// <param name="initData">reference to the buffer</param>
562
    internal DiffData(int[] initData)
4✔
563
    {
564
        data = initData;
4✔
565
        Length = initData.Length;
4✔
566
        modified = new bool[Length + 2];
4✔
567
    } // DiffData
4✔
568
} // class DiffData
569

570
// namespace
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc