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

antonvw / wex / 20437403299

22 Dec 2025 04:11PM UTC coverage: 64.322% (-0.06%) from 64.384%
20437403299

push

github

antonvw
fixed compile error

18536 of 31592 branches covered (58.67%)

Branch coverage included in aggregate %.

14771 of 20190 relevant lines covered (73.16%)

1512.23 hits per line

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

91.6
/src/factory/unified-diff-parser.cpp
1
////////////////////////////////////////////////////////////////////////////////
2
// Name:      unified-diff-parser.cpp
3
// Purpose:   Implementation of unified_diff_parser
4
//            https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html
5
// Author:    Anton van Wezenbeek
6
// Copyright: (c) 2025 Anton van Wezenbeek
7
////////////////////////////////////////////////////////////////////////////////
8

9
#include <boost/parser/parser.hpp>
10
#include <wex/core/log.h>
11
#include <wex/factory/unified-diff.h>
12

13
#include "unified-diff-parser.h"
14

15
namespace bp = boost::parser;
16

17
wex::factory::unified_diff_parser::unified_diff_parser(unified_diff* diff)
14✔
18
  : m_diff(diff)
14✔
19
{
20
  m_diff->m_range.fill({0});
14✔
21
  m_diff->m_diffs    = 0;
14✔
22
  m_diff->m_is_first = true;
14✔
23
  m_diff->m_is_last  = false;
14✔
24
  m_diff->m_type     = unified_diff::diff_t::UNKNOWN;
14✔
25
}
14✔
26

27
bool wex::factory::unified_diff_parser::parse()
14✔
28
{
29
  auto const action_diff = [this](const auto& ctx)
14✔
30
  {
31
    const auto tpl    = _attr(ctx);
14✔
32
    m_diff->m_path[0] = wex::path(std::get<0>(tpl));
14✔
33
    m_diff->m_path[1] = wex::path(std::get<1>(tpl));
14✔
34
    m_diff->m_range.fill({0});
14✔
35

36
    for (const auto& hunk : std::get<2>(tpl))
34✔
37
    {
38
      int index = 0;
20✔
39
      m_hunk_no++;
20✔
40

41
      for (const auto& number : std::get<0>(hunk))
60✔
42
      {
43
        if (const auto* val = std::get_if<std::tuple<int, int>>(&number); val)
40✔
44
        {
45
          const int range            = std::get<1>(*val);
14✔
46
          m_diff->m_range[index]     = std::abs(std::get<0>(*val));
14✔
47
          m_diff->m_range[index + 1] = range;
14✔
48

49
          if (range > 0)
14✔
50
          {
51
            m_diff->m_diffs++;
4✔
52
          }
53
        }
54
        else
55
        {
56
          m_diff->m_range[index]     = std::abs(std::get<int>(number));
26✔
57
          m_diff->m_range[index + 1] = 1;
26✔
58
          m_diff->m_diffs++;
26✔
59
        }
60

61
        index += 2;
40✔
62
      }
63

64
      if (m_hunk_no > 1)
20✔
65
      {
66
        m_diff->m_is_first = false;
13✔
67
      }
68

69
      m_diff->m_text.fill({});
20✔
70

71
      for (const auto& line : std::get<1>(hunk))
68✔
72
      {
73
        auto fix(line);
48✔
74

75
        if (line.starts_with("\n"))
48✔
76
        {
77
          fix = fix.substr(1);
8✔
78
        }
79

80
        switch (fix[0])
48!
81
        {
82
          case '+':
13✔
83
            m_diff->m_text[1].push_back(fix.substr(1));
13✔
84
            break;
13✔
85
          case '-':
20✔
86
            m_diff->m_text[0].push_back(fix.substr(1));
20✔
87
            break;
20✔
88
          case ' ':
×
89
            m_diff->m_text[0].push_back(fix.substr(1));
×
90
            m_diff->m_text[1].push_back(fix.substr(1));
×
91
            break;
×
92
        }
93
      }
94

95
      m_diff->m_type =
20✔
96
        (m_diff->m_type == unified_diff::diff_t::UNKNOWN ?
20✔
97
           unified_diff::diff_t::FIRST :
98
           unified_diff::diff_t::OTHER);
99

100
      m_diff->report_diff();
20✔
101
      m_diff->trace("found");
60✔
102
    }
103
  };
28✔
104

105
  auto const action_eoi = [this](const auto& ctx)
7✔
106
  {
107
    m_diff->m_is_last = true;
7✔
108
    m_diff->m_type    = unified_diff::diff_t::LAST;
7✔
109
    m_diff->report_diff_finish();
7✔
110
    m_diff->trace("finish");
14✔
111
  };
21✔
112

113
  // (Skip the first lines)
114
  // The unified output format starts with a two-line header:
115
  // --- from-file from-file-modification-time
116
  // +++ to-file to-file-modification-time
117
  // Next come one or more hunks of differences:
118
  // @@ from-file-line-numbers to-file-line-numbers @@
119
  // line-from-either-file
120
  // line-from-either-file...
121

122
  auto const parser_diff_lines = bp::lexeme[+(
14✔
123
    bp::char_ >> +(bp::char_ - bp::eol - "--- a/" - "@@" - "diff --"))];
124

125
  auto const parser_hunk =
126
    bp::lit("@@") >> bp::repeat(2)[bp::int_ >> ',' >> bp::int_ | bp::int_] >>
14✔
127
    bp::lit("@@") >> bp::lexeme[+(bp::char_ - bp::eol)] >> parser_diff_lines;
14✔
128

129
  auto const parser_diff = bp::lit("--- a/") >> +(bp::char_ - "+++ b/") >>
14✔
130
                           bp::lit("+++ b/") >> +(bp::char_ - "@@") >>
14✔
131
                           +parser_hunk;
14✔
132

133
  auto const parser_skip = bp::omit[*(bp::char_ - "--- a/")];
14✔
134

135
  auto const parser_all =
136
    +(parser_skip >> +parser_diff[action_diff]) >> bp::eoi[action_eoi];
14✔
137

138
  if (const auto result = bp::parse(
28!
139
        m_diff->input(),
14✔
140
        parser_all,
141
        bp::ws,
142
        log::get_level() == log::level_t::TRACE ? bp::trace::on :
14✔
143
                                                  bp::trace::off);
144
      result)
145
  {
146
    return true;
7✔
147
  }
148

149
  return false;
7✔
150
}
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

© 2026 Coveralls, Inc