import * as tmp from "tmp" ; import * as path from "path" ; import { spawnSafeSync } from "../src/spawnSafe" ; import { executeEffects } from "../src/patch/apply" ; import { parsePatchFile } from "../src/patch/parse" ; import { reversePatch } from "../src/patch/reverse" ; import { TestCase , Files } from "./testCases" ; import { appendFileSync , existsSync , writeFileSync } from "fs" ; jest . mock ( "fs-extra" , ( ) => { let workingFiles ; function setWorkingFiles ( files ) { workingFiles = files ; } function getWorkingFiles ( ) { return workingFiles ; } return { setWorkingFiles , getWorkingFiles , ensureDirSync : jest . fn ( ) , readFileSync : jest . fn ( path => getWorkingFiles ( ) [ path ] . contents ) , writeFileSync : jest . fn ( ( path , contents , opts ? ) => { getWorkingFiles ( ) [ path ] = { contents , mode : opts && typeof opts . mode === "number" ? opts . mode : 0o644 , } ; } ) , unlinkSync : jest . fn ( path => delete getWorkingFiles ( ) [ path ] ) , moveSync : jest . fn ( ( from , to ) => { getWorkingFiles ( ) [ to ] = getWorkingFiles ( ) [ from ] ; delete getWorkingFiles ( ) [ from ] ; } ) , statSync : jest . fn ( path => getWorkingFiles ( ) [ path ] ) , chmodSync : jest . fn ( ( path , mode ) => { const { contents } = getWorkingFiles ( ) [ path ] ; getWorkingFiles ( ) [ path ] = { contents , mode } ; } ) , } ; } ) ; function writeFiles ( cwd , files ) { const mkdirpSync = require ( "fs-extra/lib/mkdirs/index.js" ) . mkdirpSync ; const writeFileSync = require ( "fs" ) . writeFileSync ; Object . keys ( files ) . forEach ( filePath => { if ( ! filePath . startsWith ( ".git/" ) ) { mkdirpSync ( path . join ( cwd , path . dirname ( filePath ) ) ) ; writeFileSync ( path . join ( cwd , filePath ) , files [ filePath ] . contents , { mode : files [ filePath ] . mode , } ) ; } } ) ; } function removeLeadingSpaceOnBlankLines ( patchFileContents ) { return patchFileContents . split ( "\n" ) . map ( line => ( line === " " ? "" : line ) ) . join ( "\n" ) ; } export function executeTestCase ( testCase ) { const fs = require ( "fs-extra" ) ; function reportingFailures ( f ) { try { f ( ) ; } catch ( e ) { const data = JSON . stringify ( testCase ) + "\n\n" ; if ( ! existsSync ( "generative-test-errors.log" ) ) { writeFileSync ( "generative-test-errors.log" , data ) ; } else { appendFileSync ( "generative-test-errors.log" , data ) ; } throw e ; } } const tmpDir = tmp . dirSync ( { unsafeCleanup : true , mode : 0o100777 } ) ; spawnSafeSync ( "git" , [ "init" ] , { cwd : tmpDir . name } ) ; writeFiles ( tmpDir . name , testCase . cleanFiles ) ; spawnSafeSync ( "git" , [ "add" , "-A" ] , { cwd : tmpDir . name } ) ; spawnSafeSync ( "git" , [ "commit" , "--allow-empty" , "-m" , "blah" ] , { cwd : tmpDir . name , } ) ; if ( Object . keys ( testCase . cleanFiles ) . length > 0 ) { spawnSafeSync ( "git" , [ "rm" , "-rf" , "*" ] , { cwd : tmpDir . name , } ) ; } writeFiles ( tmpDir . name , testCase . modifiedFiles ) ; spawnSafeSync ( "git" , [ "add" , "-A" ] , { cwd : tmpDir . name } ) ; const patchResult = spawnSafeSync ( "git" , [ "diff" , "--color=never" , "--cached" ] , { cwd : tmpDir . name , logStdErrOnError : true , throwOnError : true , } ) ; const patchFileContents = patchResult . stdout . toString ( ) ; const patchFileContentsWithBlankLines = removeLeadingSpaceOnBlankLines ( patchFileContents ) ; it ( "looks the same whether parsed with blank lines or not" , ( ) => { reportingFailures ( ( ) => { expect ( parsePatchFile ( patchFileContents ) ) . toEqual ( parsePatchFile ( patchFileContentsWithBlankLines ) ) ; } ) ; } ) ; it ( "works forwards" , ( ) => { fs . setWorkingFiles ( { ... testCase . cleanFiles } ) ; reportingFailures ( ( ) => { const effects = parsePatchFile ( patchFileContents ) ; executeEffects ( effects , { dryRun : false } ) ; expect ( fs . getWorkingFiles ( ) ) . toEqual ( testCase . modifiedFiles ) ; } ) ; } ) ; it ( "works backwards" , ( ) => { fs . setWorkingFiles ( { ... testCase . modifiedFiles } ) ; reportingFailures ( ( ) => { const effects = reversePatch ( parsePatchFile ( patchFileContents ) ) ; executeEffects ( effects , { dryRun : false } ) ; expect ( fs . getWorkingFiles ( ) ) . toEqual ( testCase . cleanFiles ) ; } ) ; } ) ; }