Source: eval/driver/MergeEvaluation.js

  1. import {EvalConfig} from '../../config/EvalConfig.js';
  2. import * as fs from 'fs';
  3. import {AggregateMergeResult} from '../result/AggregateMergeResult.js';
  4. import {_3dmAdapter} from '../merge_adapters/_3dmAdapter.js';
  5. import {CpeeMergeAdapter} from '../merge_adapters/CpeeMergeAdapter.js';
  6. import {XccPatchAdapter} from '../merge_adapters/XccPatchAdapter.js';
  7. import {Logger} from '../../util/Logger.js';
  8. import {DirectoryScraper} from '../case/DirectoryScraper.js';
  9. import {MergeTestCase} from '../case/MergeTestCase.js';
  10. import {AbstractEvaluation} from './AbstractEvaluation.js';
  11. import {markdownTable} from 'markdown-table';
  12. /**
  13. * An evaluation of three-way merging algorithms using predefined test cases.
  14. */
  15. export class MergeEvaluation extends AbstractEvaluation {
  16. /**
  17. * Create a new MergeEvaluation instance.
  18. * @param {Array<MergeAdapter>} adapters The adapters of the algorithms to be
  19. * used for the evaluation.
  20. */
  21. constructor(adapters = []) {
  22. super(adapters);
  23. }
  24. /**
  25. * Create a new MergeEvaluation instance with all available merge algorithms.
  26. * @return {MergeEvaluation}
  27. */
  28. static all() {
  29. /** @type {Array<MergeAdapter>} */
  30. let adapters = [
  31. new _3dmAdapter(),
  32. new XccPatchAdapter(),
  33. ];
  34. adapters = adapters.filter((adapter) =>
  35. fs.existsSync(adapter.path + '/' + EvalConfig.FILENAMES.RUN_SCRIPT));
  36. adapters.unshift(new CpeeMergeAdapter());
  37. return new MergeEvaluation(adapters);
  38. }
  39. /**
  40. * @inheritDoc
  41. * @param {String} rootDir The path to the directory containing the
  42. * predefined merge test case directories. A merge test case directory
  43. * includes a base process tree and two branch process trees.
  44. * @override
  45. */
  46. evalAll(rootDir) {
  47. Logger.section('Merge Evaluation with Cases from ' + rootDir, this);
  48. const resultsPerAdapter = new Map();
  49. for (const adapter of this._adapters) {
  50. resultsPerAdapter.set(adapter, []);
  51. }
  52. // Collect all test case directories
  53. const caseDirs = DirectoryScraper.scrape(rootDir);
  54. for (const testCaseDir of caseDirs) {
  55. const testCase = MergeTestCase.from(testCaseDir);
  56. if (testCase == null) {
  57. Logger.warn('Skipping empty merge case directory' + testCaseDir, this);
  58. continue;
  59. }
  60. for (const adapter of this._adapters) {
  61. Logger.info(
  62. 'Running merge case ' + testCase.name +
  63. ' for ' + adapter.displayName + '...',
  64. this,
  65. );
  66. const result = adapter.evalCase(testCase);
  67. resultsPerAdapter.get(adapter).push(result);
  68. }
  69. }
  70. const aggregateResults = [];
  71. for (const [, resultsList] of resultsPerAdapter) {
  72. aggregateResults.push(AggregateMergeResult.of(resultsList));
  73. }
  74. const table = [
  75. AggregateMergeResult.header(),
  76. ...aggregateResults.map((result) => result.values()),
  77. ];
  78. Logger.result('Results of the merge evaluation:\n' +
  79. markdownTable(table), this);
  80. }
  81. }