Skip to content

Commit

Permalink
chore: update test commands to use explicit shell command syntax for …
Browse files Browse the repository at this point in the history
…clarity
  • Loading branch information
rohitpaulk committed Mar 6, 2024
1 parent 58a5961 commit b9a5f59
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 28 deletions.
67 changes: 63 additions & 4 deletions internal/stage_create_blob.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package internal

import (
"bytes"
"compress/zlib"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"strings"

"github.com/codecrafters-io/tester-utils/bytes_diff_visualizer"
logger "github.com/codecrafters-io/tester-utils/logger"
"github.com/codecrafters-io/tester-utils/test_case_harness"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
Expand All @@ -24,15 +30,15 @@ func testCreateBlob(harness *test_case_harness.TestCaseHarness) error {

executable.WorkingDir = tempDir

logger.Debugf("Running ./your_git.sh init")
logger.Infof("$ ./your_git.sh init")
_, err = executable.Run("init")
if err != nil {
return err
}

logger.Debugf("Writing sample file")
sampleFileName := fmt.Sprintf("%s.txt", randomStringShort())
sampleFileContents := randomString()
logger.Infof("$ echo %q > %s", sampleFileContents, sampleFileName)
err = ioutil.WriteFile(
path.Join(tempDir, sampleFileName),
[]byte(sampleFileContents),
Expand All @@ -44,7 +50,7 @@ func testCreateBlob(harness *test_case_harness.TestCaseHarness) error {

expectedSha := plumbing.ComputeHash(plumbing.BlobObject, []byte(sampleFileContents))

logger.Debugf("Running ./your_git.sh hash-object -w %s", sampleFileName)
logger.Infof("$ ./your_git.sh hash-object -w %s", sampleFileName)
result, err := executable.Run("hash-object", "-w", sampleFileName)
if err != nil {
return err
Expand All @@ -54,11 +60,20 @@ func testCreateBlob(harness *test_case_harness.TestCaseHarness) error {
return err
}

if len(strings.TrimSpace(string(result.Stdout))) != 40 {
return fmt.Errorf("Expected a 40-char SHA (%q) as output. Got: %q", expectedSha.String(), strings.TrimSpace(string(result.Stdout)))
}

actualShaString := strings.TrimSpace(string(result.Stdout))

if err = assertStdoutContains(result, expectedSha.String()); err != nil {
printFriendlyBlobFileDiff(logger, tempDir, actualShaString, expectedSha.String(), sampleFileContents)
return err
}

logger.Debugf("Running git cat-file -p %s", expectedSha.String())
logger.Successf("Output is valid.")

logger.Infof("$ git cat-file -p %s", expectedSha.String())
r, err := git.PlainOpen(tempDir)
if err != nil {
return err
Expand All @@ -85,5 +100,49 @@ func testCreateBlob(harness *test_case_harness.TestCaseHarness) error {
return fmt.Errorf("Expected %q as file contents, got: %q", expected, actual)
}

logger.Successf("Blob file contents are valid.")

return nil
}

func printFriendlyBlobFileDiff(logger *logger.Logger, repoDir, actualSha, expectedSha, contents string) {
actualFileRelativePath := path.Join(".git", "objects", actualSha[:2], actualSha[2:])
actualFilePath := path.Join(repoDir, actualFileRelativePath)
expectedDecompressedFileContents := []byte("blob " + fmt.Sprint(len(contents)) + "\x00" + contents)
logger.Infof("Expected SHA: %s", expectedSha)
logger.Infof("Returned SHA: %s", actualSha)

actualFileContents, err := os.ReadFile(actualFilePath)
if err != nil {
logger.Infof("Note: Did not find file at %q to render diff. Assuming contents are empty.", actualFileRelativePath)

var in bytes.Buffer
b := []byte("")
w := zlib.NewWriter(&in)
w.Write(b)
w.Close()

actualFileContents = in.Bytes()
}

compressedActualFileReader, err := zlib.NewReader(bytes.NewReader(actualFileContents))
if err != nil {
logger.Infof("Error decompressing file at %q to render diff. Assuming contents are empty.", actualFileRelativePath)
compressedActualFileReader, _ = zlib.NewReader(bytes.NewReader([]byte{}))
}

decompressedActualGitObjectFileContents, err := io.ReadAll(compressedActualFileReader)
if err != nil {
logger.Infof("Note: Error decompressing file at %q. Assuming contents are empty.", actualFileRelativePath)
}

lines := bytes_diff_visualizer.VisualizeByteDiff(decompressedActualGitObjectFileContents, expectedDecompressedFileContents)
logger.Errorf("Git object file doesn't match official Git implementation. Diff after zlib decompression:")
logger.Errorf("")

for _, line := range lines {
logger.Plainln(line)
}

logger.Errorf("")
}
14 changes: 14 additions & 0 deletions internal/stages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ func TestStages(t *testing.T) {
StdoutFixturePath: "./test_helpers/fixtures/read_blob",
NormalizeOutputFunc: normalizeTesterOutput,
},
"create_blob_failure": {
UntilStageSlug: "create_blob",
CodePath: "./test_helpers/stages/create_blob_failure",
ExpectedExitCode: 0,
StdoutFixturePath: "./test_helpers/fixtures/create_blob_failure",
NormalizeOutputFunc: normalizeTesterOutput,
},
"create_blob_no_file": {
UntilStageSlug: "create_blob",
CodePath: "./test_helpers/stages/create_blob_no_file",
ExpectedExitCode: 0,
StdoutFixturePath: "./test_helpers/fixtures/create_blob_no_file",
NormalizeOutputFunc: normalizeTesterOutput,
},
"create_blob_success": {
UntilStageSlug: "create_blob",
CodePath: "./test_helpers/stages/create_blob",
Expand Down
10 changes: 6 additions & 4 deletions internal/test_helpers/fixtures/create_blob
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ Debug = true
[stage-2] Test passed.

[stage-3] Running tests for Stage #3: create_blob
[stage-3] Running ./your_git.sh init
[stage-3] $ ./your_git.sh init
[your_program] Initialized git directory
[stage-3] Writing sample file
[stage-3] Running ./your_git.sh hash-object -w donkey.txt
[stage-3] $ echo "dumpty dooby doo donkey horsey vanilla" > donkey.txt
[stage-3] $ ./your_git.sh hash-object -w donkey.txt
[your_program] 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Running git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Output is valid.
[stage-3] $ git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Blob file contents are valid.
[stage-3] Test passed.
10 changes: 6 additions & 4 deletions internal/test_helpers/fixtures/read_tree
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ Debug = true
[stage-2] Test passed.

[stage-3] Running tests for Stage #3: create_blob
[stage-3] Running ./your_git.sh init
[stage-3] $ ./your_git.sh init
[your_program] Initialized git directory
[stage-3] Writing sample file
[stage-3] Running ./your_git.sh hash-object -w donkey.txt
[stage-3] $ echo "dumpty dooby doo donkey horsey vanilla" > donkey.txt
[stage-3] $ ./your_git.sh hash-object -w donkey.txt
[your_program] 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Running git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Output is valid.
[stage-3] $ git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Blob file contents are valid.
[stage-3] Test passed.

[stage-4] Running tests for Stage #4: read_tree
Expand Down
10 changes: 6 additions & 4 deletions internal/test_helpers/fixtures/read_tree_exit_code_failure
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ Debug = true
[stage-2] Test passed.

[stage-3] Running tests for Stage #3: create_blob
[stage-3] Running ./your_git.sh init
[stage-3] $ ./your_git.sh init
[your_program] Initialized git directory
[stage-3] Writing sample file
[stage-3] Running ./your_git.sh hash-object -w donkey.txt
[stage-3] $ echo "dumpty dooby doo donkey horsey vanilla" > donkey.txt
[stage-3] $ ./your_git.sh hash-object -w donkey.txt
[your_program] 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Running git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Output is valid.
[stage-3] $ git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Blob file contents are valid.
[stage-3] Test passed.

[stage-4] Running tests for Stage #4: read_tree
Expand Down
10 changes: 6 additions & 4 deletions internal/test_helpers/fixtures/write_tree
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ Debug = true
[stage-2] Test passed.

[stage-3] Running tests for Stage #3: create_blob
[stage-3] Running ./your_git.sh init
[stage-3] $ ./your_git.sh init
[your_program] Initialized git directory
[stage-3] Writing sample file
[stage-3] Running ./your_git.sh hash-object -w donkey.txt
[stage-3] $ echo "dumpty dooby doo donkey horsey vanilla" > donkey.txt
[stage-3] $ ./your_git.sh hash-object -w donkey.txt
[your_program] 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Running git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Output is valid.
[stage-3] $ git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Blob file contents are valid.
[stage-3] Test passed.

[stage-4] Running tests for Stage #4: read_tree
Expand Down
10 changes: 6 additions & 4 deletions internal/test_helpers/fixtures/write_tree_err_not_exist_fail
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ Debug = true
[stage-2] Test passed.

[stage-3] Running tests for Stage #3: create_blob
[stage-3] Running ./your_git.sh init
[stage-3] $ ./your_git.sh init
[your_program] Initialized git directory
[stage-3] Writing sample file
[stage-3] Running ./your_git.sh hash-object -w donkey.txt
[stage-3] $ echo "dumpty dooby doo donkey horsey vanilla" > donkey.txt
[stage-3] $ ./your_git.sh hash-object -w donkey.txt
[your_program] 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Running git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Output is valid.
[stage-3] $ git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Blob file contents are valid.
[stage-3] Test passed.

[stage-4] Running tests for Stage #4: read_tree
Expand Down
10 changes: 6 additions & 4 deletions internal/test_helpers/fixtures/write_tree_fail
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ Debug = true
[stage-2] Test passed.

[stage-3] Running tests for Stage #3: create_blob
[stage-3] Running ./your_git.sh init
[stage-3] $ ./your_git.sh init
[your_program] Initialized git directory
[stage-3] Writing sample file
[stage-3] Running ./your_git.sh hash-object -w donkey.txt
[stage-3] $ echo "dumpty dooby doo donkey horsey vanilla" > donkey.txt
[stage-3] $ ./your_git.sh hash-object -w donkey.txt
[your_program] 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Running git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Output is valid.
[stage-3] $ git cat-file -p 32eb24247f1cc0f2aa44da05b849392063a9b9e7
[stage-3] Blob file contents are valid.
[stage-3] Test passed.

[stage-4] Running tests for Stage #4: read_tree
Expand Down
41 changes: 41 additions & 0 deletions internal/test_helpers/stages/create_blob_failure/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import sys
import os
import zlib

import hashlib
import pathlib


def main():
command = sys.argv[1]
if command == "init":
os.mkdir(".git")
os.mkdir(".git/objects")
os.mkdir(".git/refs")
with open(".git/HEAD", "w") as f:
f.write("ref: refs/heads/master\n")

print("Initialized git directory")
elif command == "hash-object":
assert sys.argv[2] == "-w"
filepath = sys.argv[3]
contents = open(filepath).read()
header = f"blob{len(contents)}\0"
store = (header + contents).encode()
sha = hashlib.sha1(store).hexdigest()
print(sha)
zlib_store = zlib.compress(store)
path = f".git/objects/{sha[0:2]}/{sha[2:]}"
os.makedirs(os.path.dirname(path), exist_ok=True)
open(path, "wb").write(zlib_store)
elif command == "cat-file":
sha = sys.argv[3]
obj_path = f".git/objects/{sha[0:2]}/{sha[2:]}"
compressed = open(obj_path, "rb").read()
uncompressed = zlib.decompress(compressed)
sys.stdout.buffer.write(uncompressed.split(b"\0")[-1])
else:
raise RuntimeError(f"Unknown command: #{command}")


main()
11 changes: 11 additions & 0 deletions internal/test_helpers/stages/create_blob_failure/codecrafters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is the current stage that you're on.
#
# Whenever you want to advance to the next stage,
# bump this to the next number.
current_stage: 1

# Set this to true if you want debug logs.
#
# These can be VERY verbose, so we suggest turning them off
# unless you really need them.
debug: true
3 changes: 3 additions & 0 deletions internal/test_helpers/stages/create_blob_failure/your_git.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
export PYTHONPATH="$(dirname "$0")"
exec python3 -m app "$@"
32 changes: 32 additions & 0 deletions internal/test_helpers/stages/create_blob_no_file/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import sys
import os
import zlib

import hashlib
import pathlib


def main():
command = sys.argv[1]
if command == "init":
os.mkdir(".git")
os.mkdir(".git/objects")
os.mkdir(".git/refs")
with open(".git/HEAD", "w") as f:
f.write("ref: refs/heads/master\n")

print("Initialized git directory")
elif command == "hash-object":
assert sys.argv[2] == "-w"
print("afa8b20484a29b438370b623ced459c9409fcc05") # Dummy
elif command == "cat-file":
sha = sys.argv[3]
obj_path = f".git/objects/{sha[0:2]}/{sha[2:]}"
compressed = open(obj_path, "rb").read()
uncompressed = zlib.decompress(compressed)
sys.stdout.buffer.write(uncompressed.split(b"\0")[-1])
else:
raise RuntimeError(f"Unknown command: #{command}")


main()
11 changes: 11 additions & 0 deletions internal/test_helpers/stages/create_blob_no_file/codecrafters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is the current stage that you're on.
#
# Whenever you want to advance to the next stage,
# bump this to the next number.
current_stage: 1

# Set this to true if you want debug logs.
#
# These can be VERY verbose, so we suggest turning them off
# unless you really need them.
debug: true
3 changes: 3 additions & 0 deletions internal/test_helpers/stages/create_blob_no_file/your_git.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
export PYTHONPATH="$(dirname "$0")"
exec python3 -m app "$@"

0 comments on commit b9a5f59

Please sign in to comment.