Repository: nodejs/node
Pull request: src: dump snapshot source with node:generate_default_snapshot_source

This helps diffing snapshots when the reproducibility gets broken.

<!--
Before submitting a pull request, please read:

- the CONTRIBUTING guide at https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md
- the commit message formatting guidelines at
  https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md#commit-message-guidelines

For code changes:
1. Include tests for any bug fixes or new features.
2. Update documentation if relevant.
3. Ensure that `make -j4 test` (UNIX), or `vcbuild test` (Windows) passes.

If you believe this PR should be highlighted in the Node.js CHANGELOG
please add the `notable-change` label.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.
-->


Changed files:
filename: src/node.cc
patch: @@ -1374,6 +1374,21 @@ ExitCode GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr,
   DCHECK(snapshot_config.builder_script_path.has_value());
   const std::string& builder_script =
       snapshot_config.builder_script_path.value();
+
+  // For the special builder node:generate_default_snapshot_source, generate
+  // the snapshot as C++ source and write it to snapshot.cc (for testing).
+  if (builder_script == "node:generate_default_snapshot_source") {
+    // Reset to empty to generate from scratch.
+    snapshot_config.builder_script_path = {};
+    exit_code =
+        node::SnapshotBuilder::GenerateAsSource("snapshot.cc",
+                                                args_maybe_patched,
+                                                result->exec_args(),
+                                                snapshot_config,
+                                                true /* use_array_literals */);
+    return exit_code;
+  }
+
   // node:embedded_snapshot_main indicates that we are using the
   // embedded snapshot and we are not supposed to clean it up.
   if (builder_script == "node:embedded_snapshot_main") {

filename: test/parallel/test-snapshot-reproducible.js
patch: @@ -21,7 +21,7 @@ function generateSnapshot() {
       '--random_seed=42',
       '--predictable',
       '--build-snapshot',
-      'node:generate_default_snapshot',
+      'node:generate_default_snapshot_source',
     ],
     {
       env: { ...process.env, NODE_DEBUG_NATIVE: 'SNAPSHOT_SERDES' },
@@ -38,33 +38,10 @@ function generateSnapshot() {
       },
     }
   );
-  const blobPath = tmpdir.resolve('snapshot.blob');
-  return fs.readFileSync(blobPath);
+  const outputPath = tmpdir.resolve('snapshot.cc');
+  return fs.readFileSync(outputPath, 'utf-8').split('\n');
 }
 
-const buf1 = generateSnapshot();
-const buf2 = generateSnapshot();
-
-const diff = [];
-let offset = 0;
-const step = 16;
-do {
-  const length = Math.min(buf1.length - offset, step);
-  const slice1 = buf1.slice(offset, offset + length).toString('hex');
-  const slice2 = buf2.slice(offset, offset + length).toString('hex');
-  if (slice1 !== slice2) {
-    diff.push({ offset: '0x' + (offset).toString(16), slice1, slice2 });
-  }
-  offset += length;
-} while (offset < buf1.length);
-
-assert.strictEqual(offset, buf1.length);
-if (offset < buf2.length) {
-  const length = Math.min(buf2.length - offset, step);
-  const slice2 = buf2.slice(offset, offset + length).toString('hex');
-  diff.push({ offset, slice1: '', slice2 });
-  offset += length;
-} while (offset < buf2.length);
-
-assert.deepStrictEqual(diff, []);
-assert.strictEqual(buf1.length, buf2.length);
+const source1 = generateSnapshot();
+const source2 = generateSnapshot();
+assert.deepStrictEqual(source1, source2);