LCOV - code coverage report
Current view: top level - src/lib - InlineJSONFormatter.cpp (source / functions) Hit Total Coverage
Test: mediawiki/php/wikidiff2 test coverage report Lines: 156 164 95.1 %
Date: 2023-07-04 10:20:16 Functions: 10 11 90.9 %

          Line data    Source code
       1             : 
       2             : #include "InlineJSONFormatter.h"
       3             : #include <iomanip>
       4             : 
       5             : namespace wikidiff2 {
       6             : 
       7           0 : const char * InlineJSONFormatter::getName()
       8             : {
       9           0 :     return "inlineJSON";
      10             : }
      11             : 
      12          11 : void InlineJSONFormatter::printFileHeader()
      13             : {
      14          11 :     result << "{\"diff\": [";
      15          11 : }
      16             : 
      17          11 : void InlineJSONFormatter::printFileFooter()
      18             : {
      19          11 :     result << "]}";
      20          11 : }
      21             : 
      22          23 : void InlineJSONFormatter::printAdd(const String& line, int leftLine, int rightLine,
      23             :     int offsetFrom, int offsetTo)
      24             : {
      25          23 :     printAddDelete(line, DiffType::AddLine, toString(rightLine), offsetFrom, offsetTo);
      26          23 : }
      27             : 
      28          46 : void InlineJSONFormatter::printDelete(const String& line, int leftLine, int rightLine,
      29             :     int offsetFrom, int offsetTo)
      30             : {
      31          46 :     printAddDelete(line, DiffType::DeleteLine, "", offsetFrom, offsetTo);
      32          46 : }
      33             : 
      34             : /**
      35             :  * Shared code for printAdd and printDelete
      36             :  */
      37          69 : void InlineJSONFormatter::printAddDelete(const String& line, DiffType diffType, const String& lineNumber,
      38             :     int offsetFrom, int offsetTo) {
      39          69 :     if (hasResults)
      40          68 :         result << ",";
      41             : 
      42         115 :     String lineNumberJSON = lineNumber.length() == 0 ? "" : ", \"lineNumber\": " + lineNumber;
      43          69 :     result << "{\"type\": " << (int)diffType;
      44          69 :     if (lineNumber.length()) {
      45          23 :         result << ", \"lineNumber\": " << lineNumber;
      46             :     }
      47          69 :     result << ", \"text\": \"";
      48          69 :     printEscapedJSON(line);
      49          69 :     result << "\"";
      50          69 :     appendOffset(offsetFrom, offsetTo);
      51          69 :     result << "}";
      52             : 
      53          69 :     hasResults = true;
      54          69 : }
      55             : 
      56          44 : void InlineJSONFormatter::printWordDiff(const WordDiff & worddiff, int leftLine,
      57             :     int rightLine, int offsetFrom, int offsetTo, bool printLeft, bool printRight,
      58             :     const String & srcAnchor, const String & dstAnchor, bool moveDirectionDownwards)
      59             : {
      60          44 :     bool moved = printLeft != printRight,
      61          44 :     isMoveSrc = moved && printLeft;
      62             : 
      63          44 :     if (hasResults)
      64          37 :         result << ",";
      65          44 :     if (moved) {
      66          18 :         LinkDirection direction = moveDirectionDownwards ? LinkDirection::Down : LinkDirection::Up;
      67          18 :         if (isMoveSrc) {
      68           9 :             result << "{\"type\": " << (int)DiffType::MoveSource
      69             :                 << ", \"moveInfo\": "
      70             :                 << "{\"id\": \"" << srcAnchor << "\", \"linkId\": \"" << dstAnchor
      71           9 :                 << "\", \"linkDirection\": " << (int)direction << "}"
      72           9 :                 << ", \"text\": \"";
      73             :         } else {
      74           9 :             result << "{\"type\": " << (int)DiffType::MoveDestination
      75           9 :                 << ", \"lineNumber\": " << rightLine
      76             :                 << ", \"moveInfo\": "
      77             :                 << "{\"id\": \"" << srcAnchor << "\", \"linkId\": \"" << dstAnchor
      78           9 :                 << "\", \"linkDirection\": " << (int)direction << "}"
      79           9 :                 << ", \"text\": \"";
      80             :         }
      81             :     } else {
      82          26 :         result << "{\"type\": " << (int)DiffType::Change
      83          26 :             << ", \"lineNumber\": " << rightLine
      84          26 :             << ", \"text\": \"";
      85             :     }
      86          44 :     hasResults = true;
      87             : 
      88          44 :     unsigned int rangeCalcResult = 0;
      89          88 :     String ranges;
      90         212 :     for (unsigned i = 0; i < worddiff.size(); ++i) {
      91         168 :         const DiffOp<Word> & op = worddiff[i];
      92             :         unsigned long n;
      93             :         int j;
      94         168 :         if (op.op == DiffOp<Word>::copy) {
      95          94 :             n = op.from.size();
      96        1604 :             for (j=0; j<n; j++) {
      97        1510 :                 const Word & word = *op.from[j];
      98        1510 :                 rangeCalcResult += word.size();
      99        1510 :                 printEscapedJSON(word);
     100             :             }
     101          74 :         } else if (op.op == DiffOp<Word>::del) {
     102          15 :             n = op.from.size();
     103          15 :             unsigned int start = rangeCalcResult;
     104          15 :             unsigned int length = 0;
     105          72 :             for (j=0; j<n; j++) {
     106          57 :                 const Word & word = *op.from[j];
     107             : 
     108          57 :                 length += word.size();
     109          57 :                 rangeCalcResult += word.size();
     110          57 :                 printEscapedJSON(word);
     111             :             }
     112             : 
     113          15 :             if (!isMoveSrc) {
     114          10 :                 if (ranges.length() > 1)
     115           6 :                     ranges.append(",");
     116          20 :                 ranges.append("{\"start\": " + toString(start) + ", \"length\": " +
     117          40 :                     toString(length) + ", \"type\": " + toString(HighlightType::Delete) +
     118          10 :                     " }");
     119             :             }
     120          59 :         } else if (op.op == DiffOp<Word>::add) {
     121          50 :             if (isMoveSrc)
     122          10 :                 continue;
     123          40 :             n = op.to.size();
     124          40 :             unsigned int start = rangeCalcResult;
     125          40 :             unsigned int length = 0;
     126         150 :             for (j=0; j<n; j++) {
     127         110 :                 const Word & word = *op.to[j];
     128             : 
     129         110 :                 length += word.size();
     130         110 :                 rangeCalcResult += word.size();
     131         110 :                 printEscapedJSON(word);
     132             :             }
     133             : 
     134          40 :             if (ranges.length() > 1)
     135          17 :                 ranges.append(",");
     136          80 :             ranges.append("{\"start\": " + toString(start) + ", \"length\": " +
     137         120 :                 toString(length) + ", \"type\": " + toString(HighlightType::Add) + " }");
     138             : 
     139           9 :         } else if (op.op == DiffOp<Word>::change) {
     140           9 :             n = op.from.size();
     141           9 :             unsigned int start = rangeCalcResult;
     142           9 :             unsigned int length = 0;
     143       13047 :             for (j=0; j<n; j++) {
     144       13038 :                 const Word & word = *op.from[j];
     145             : 
     146       13038 :                 length += word.size();
     147       13038 :                 rangeCalcResult += word.size();
     148       13038 :                 printEscapedJSON(word);
     149             :             }
     150             : 
     151           9 :             if (!isMoveSrc) {
     152           7 :                 if (ranges.length() > 1)
     153           4 :                     ranges.append(",");
     154          14 :                 ranges.append("{\"start\": " + toString(start) + ", \"length\": " +
     155          28 :                     toString(length) + ", \"type\": " + toString(HighlightType::Delete) +
     156           7 :                     " }");
     157             :             }
     158             : 
     159           9 :             if (isMoveSrc)
     160           2 :                 continue;
     161           7 :             n = op.to.size();
     162           7 :             start = rangeCalcResult;
     163           7 :             length = 0;
     164       12013 :             for (j=0; j<n; j++) {
     165       12006 :                 const Word & word = *op.to[j];
     166             : 
     167       12006 :                 length += word.size();
     168       12006 :                 rangeCalcResult += word.size();
     169             : 
     170       12006 :                 printEscapedJSON(word);
     171             :             }
     172             : 
     173           7 :             if (ranges.length() > 1)
     174           7 :                 ranges.append(",");
     175          14 :             ranges.append("{\"start\": " + toString(start) + ", \"length\": " +
     176          21 :                 toString(length) + ", \"type\": " + toString(HighlightType::Add) + " }");
     177             :         }
     178             :     }
     179             : 
     180          44 :     result << "\"";
     181          44 :     appendOffset(offsetFrom, offsetTo);
     182          44 :     if (moved && isMoveSrc) {
     183           9 :         result << "}";
     184             :     } else {
     185          35 :         result << ", \"highlightRanges\": [" << ranges << "]}";
     186             :     }
     187          44 : }
     188             : 
     189          21 : void InlineJSONFormatter::printBlockHeader(int leftLine, int rightLine)
     190             : {
     191             :     //inline diff json not setup to print this
     192          21 : }
     193             : 
     194         137 : void InlineJSONFormatter::printContext(const String & input, int leftLine, int rightLine,
     195             :     int offsetFrom, int offsetTo)
     196             : {
     197         137 :     if (hasResults)
     198         134 :         result << ",";
     199             : 
     200         137 :     result << "{\"type\": " << (int)DiffType::Context
     201         137 :         << ", \"lineNumber\": " << rightLine << ", \"text\": \"";
     202         137 :     printEscapedJSON(input);
     203         137 :     result << "\"";
     204         137 :     appendOffset(offsetFrom, offsetTo);
     205         137 :     result << "}";
     206         137 :     hasResults = true;
     207         137 : }
     208             : 
     209             : /**
     210             :  * Append a String range to the output, escaping it for JSON
     211             :  */
     212       26927 : void InlineJSONFormatter::printEscapedJSON(StringIterator start, StringIterator end) {
     213       62278 :     for (auto c = start; c != end; c++) {
     214       35351 :         switch (*c) {
     215          15 :             case '"': result << "\\\""; break;
     216          22 :             case '\\': result << "\\\\"; break;
     217           0 :             case '\b': result << "\\b"; break;
     218           2 :             case '\f': result << "\\f"; break;
     219           0 :             case '\n': result << "\\n"; break;
     220           1 :             case '\r': result << "\\r"; break;
     221           1 :             case '\t': result << "\\t"; break;
     222       35310 :             default:
     223       35310 :             if ('\x00' <= *c && *c <= '\x1f') {
     224           0 :                 char origFill = result.fill();
     225           0 :                 result << "\\u"
     226           0 :                     << std::hex << std::setw(4) << std::setfill('0') << (int)*c
     227           0 :                     << std::setfill(origFill) << std::dec;
     228             :             } else {
     229       35310 :                 result.put(*c);
     230             :             }
     231             :         }
     232             :     }
     233       26927 : }
     234             : 
     235             : /**
     236             :  * Append current offsets to the output
     237             :  */
     238         250 : void InlineJSONFormatter::appendOffset(int offsetFrom, int offsetTo) {
     239             :     result << ", \"offset\": {"
     240         250 :         << "\"from\": ";
     241         250 :     if (offsetFrom > -1) {
     242         218 :         result << offsetFrom;
     243             :     } else {
     244          32 :         result << "null";
     245             :     }
     246         250 :     result << ",\"to\": ";
     247         250 :     if (offsetTo > -1) {
     248         195 :         result << offsetTo;
     249             :     } else {
     250          55 :         result << "null";
     251             :     }
     252         250 :     result << "}";
     253         250 : }
     254             : 
     255             : } // namespace wikidiff2

Generated by: LCOV version 1.13