[gjs] Write function line number before unique key in FN entries.



commit 96628cb56d3822ee4138179c5c7981b85438088a
Author: Sam Spilsbury <smspillaz gmail com>
Date:   Mon Jan 5 09:25:35 2015 +0800

    Write function line number before unique key in FN entries.
    
    Before we were not writing the line number before the unique key
    but instead as part of the unique key. This is technically not
    compliant with the lcov specification, which requires th
    following:
    
        FN:<line number>,<function name>
    
    For some reason, genhtml never complained about this and silently
    just accepted the function names. Other tools that work with lcov
    data, like lcov_cobertura and lcov-result-merge are far less
    forgiving.
    
    Fixes BGO #742362

 gjs/coverage.cpp           |   18 +++++++++++--
 modules/coverage.js        |    3 ++
 test/gjs-test-coverage.cpp |   61 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 77 insertions(+), 5 deletions(-)
---
diff --git a/gjs/coverage.cpp b/gjs/coverage.cpp
index 2f4d843..73ed9e8 100644
--- a/gjs/coverage.cpp
+++ b/gjs/coverage.cpp
@@ -70,6 +70,7 @@ typedef struct _GjsCoverageBranch {
 
 typedef struct _GjsCoverageFunction {
     char         *key;
+    unsigned int line_number;
     unsigned int hit_count;
 } GjsCoverageFunction;
 
@@ -126,7 +127,7 @@ write_function_foreach_func(gpointer value,
     GOutputStream       *stream = (GOutputStream *) user_data;
     GjsCoverageFunction *function = (GjsCoverageFunction *) value;
 
-    g_output_stream_printf(stream, NULL, NULL, NULL, "FN:%s\n", function->key);
+    g_output_stream_printf(stream, NULL, NULL, NULL, "FN:%d,%s\n", function->line_number, function->key);
 }
 
 static void
@@ -503,9 +504,11 @@ get_executed_lines_for(GjsCoverage *coverage,
 static void
 init_covered_function(GjsCoverageFunction *function,
                       char                *key,
+                      unsigned int        line_number,
                       unsigned int        hit_count)
 {
     function->key = key;
+    function->line_number = line_number;
     function->hit_count = hit_count;
 }
 
@@ -558,12 +561,21 @@ convert_and_insert_function_decl(GArray    *array,
         return FALSE;
     }
 
-    unsigned int line_number = JSVAL_TO_INT(hit_count_property_value);
+    jsval line_number_property_value;
+    if (!JS_GetProperty(context, object, "line", &line_number_property_value) ||
+        !JSVAL_IS_INT(line_number_property_value)) {
+        gjs_throw(context, "Failed to get line property for function object");
+        return FALSE;
+    }
+
+    unsigned int line_number = JSVAL_TO_INT(line_number_property_value);
+    unsigned int hit_count = JSVAL_TO_INT(hit_count_property_value);
 
     GjsCoverageFunction info;
     init_covered_function(&info,
                           utf8_string,
-                          line_number);
+                          line_number,
+                          hit_count);
 
     g_array_append_val(array, info);
 
diff --git a/modules/coverage.js b/modules/coverage.js
index e2b98bc..1c29992 100644
--- a/modules/coverage.js
+++ b/modules/coverage.js
@@ -591,7 +591,10 @@ function _convertFunctionCountersToArray(functionCounters) {
      * of that object */
     for (let key in functionCounters) {
         let func = functionCounters[key];
+        /* The name of the function contains its line, after the first
+         * colon. Split the name and retrieve it here */
         arrayReturn.push({ name: key,
+                           line: Number(key.split(':')[1]),
                            hitCount: func.hitCount });
     }
 
diff --git a/test/gjs-test-coverage.cpp b/test/gjs-test-coverage.cpp
index 462c001..28929a7 100644
--- a/test/gjs-test-coverage.cpp
+++ b/test/gjs-test-coverage.cpp
@@ -802,6 +802,10 @@ has_function_name(const char *line,
     /* Advance past "FN:" */
     line += 3;
 
+    /* Advance past the first comma */
+    while (*(line - 1) != ',')
+        ++line;
+
     return strncmp(line,
                    expected_function_name,
                    strlen(expected_function_name)) == 0;
@@ -835,8 +839,7 @@ test_function_names_written_to_coverage_data(gpointer      fixture_data,
     };
     const gsize expected_function_names_len = G_N_ELEMENTS(expected_function_names);
 
-    /* There are two possible branches here, the second should be taken
-     * and the first should not have been */
+    /* Just expect that we've got an FN matching out expected function names */
     g_assert(coverage_data_matches_values_for_key(coverage_data_contents,
                                                   "FN:",
                                                   expected_function_names_len,
@@ -846,6 +849,56 @@ test_function_names_written_to_coverage_data(gpointer      fixture_data,
     g_free(coverage_data_contents);
 }
 
+static gboolean
+has_function_line(const char *line,
+                  gpointer    user_data)
+{
+    /* User data is const char ** */
+    const char *expected_function_line = *((const char **) user_data);
+
+    /* Advance past "FN:" */
+    line += 3;
+
+    return strncmp(line,
+                   expected_function_line,
+                   strlen(expected_function_line)) == 0;
+}
+
+static void
+test_function_lines_written_to_coverage_data(gpointer      fixture_data,
+                                             gconstpointer user_data)
+{
+    GjsCoverageToSingleOutputFileFixture *fixture = (GjsCoverageToSingleOutputFileFixture *) fixture_data;
+
+    const char *script_with_functions =
+        "function f(){}\n"
+        "\n"
+        "function g(){}\n";
+
+    write_to_file_at_beginning(fixture->base_fixture.temporary_js_script_open_handle,
+                               script_with_functions);
+
+    char *coverage_data_contents =
+        eval_script_and_get_coverage_data(fixture->base_fixture.context,
+                                          fixture->base_fixture.coverage,
+                                          fixture->base_fixture.temporary_js_script_filename,
+                                          fixture->output_file_directory,
+                                          NULL);
+    const char * expected_function_lines[] = {
+        "1",
+        "3"
+    };
+    const gsize expected_function_lines_len = G_N_ELEMENTS(expected_function_lines);
+
+    g_assert(coverage_data_matches_values_for_key(coverage_data_contents,
+                                                  "FN:",
+                                                  expected_function_lines_len,
+                                                  has_function_line,
+                                                  (gpointer) expected_function_lines,
+                                                  sizeof(const char *)));
+    g_free(coverage_data_contents);
+}
+
 typedef struct _FunctionHitCountData {
     const char   *function;
     unsigned int hit_count_minimum;
@@ -1435,6 +1488,10 @@ void gjs_test_add_tests_for_coverage()
                          &coverage_to_single_output_fixture,
                          test_function_names_written_to_coverage_data,
                          NULL);
+    add_test_for_fixture("/gjs/coverage/function_lines_written_to_coverage_data",
+                         &coverage_to_single_output_fixture,
+                         test_function_lines_written_to_coverage_data,
+                         NULL);
     add_test_for_fixture("/gjs/coverage/function_hit_counts_written_to_coverage_data",
                          &coverage_to_single_output_fixture,
                          test_function_hit_counts_written_to_coverage_data,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]