Skip to content

Commit

Permalink
Merge pull request #1 from neu-se/publish
Browse files Browse the repository at this point in the history
Adding files for public release
  • Loading branch information
james-perretta authored Mar 1, 2023
2 parents 7df4bbd + 2133fec commit 0d49e38
Show file tree
Hide file tree
Showing 105 changed files with 5,663 additions and 2 deletions.
10 changes: 10 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
indent_size = 4

95 changes: 95 additions & 0 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: Python package

on: [push]

jobs:
lint:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install pip-tools
pip-sync requirements-dev.txt
- name: Lint with pycdestyle, isort, and pyright
run: |
sh lint.sh
unittest:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install racket
run: |
sudo add-apt-repository ppa:plt/racket
sudo apt-get update
sudo apt-get install racket
racket --version
- name: Install prod dependencies only
run: |
python -m pip install --upgrade pip
python -m pip install pip-tools
pip-sync requirements.txt
- name: Run unit tests
run: |
python3 -m unittest discover
e2etest:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install racket
run: |
sudo add-apt-repository ppa:plt/racket
sudo apt-get update
sudo apt-get install racket
racket --version
raco pkg install al2-test-runner
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Build and install package
run: |
python3 -m pip install --upgrade pip
python3 -m pip install build
python3 -m build
python3 -m pip install $(ls -1 dist/*.whl | tail -n 1)
- name: Run mutation analysis e2e tests
working-directory: racket_mutation_analysis/mutation_analysis/e2e
run: |
./run_e2e_test.sh tests/all_tests_all_mutants 0
./run_e2e_test.sh tests/exclude_test_all_mutants 0
./run_e2e_test.sh tests/include_test_all_mutants 1
./run_e2e_test.sh tests/include_test_exclude_mutants 1
./run_e2e_test.sh tests/include_test_include_mutants 1
./run_e2e_test.sh tests/include_test_include_mutants2 0
./run_e2e_test.sh tests/skip_false_positive_check 0
./run_e2e_test.sh tests/stop_after_false_positive_check_0_exit_status 0
./run_e2e_test.sh tests/stop_after_false_positive_check_1_exit_status 1
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,11 @@ dmypy.json

# Pyre type checker
.pyre/

**/.DS_Store

cmp.rkd
cond.skt
sample.rkt
.vscode/settings.json
racket_mutation_analysis/mutation_analysis/e2e/actual_output.txt
59 changes: 57 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,57 @@
# MACKET
A mutation analysis tool for Racket
# Racket Mutation Testing

## Installing the Package
Install the latest Python wheel as follows (requires Python >= 3.10):
```
python3 -m pip install $(ls -1 dist/*.whl | tail -n 1)
```

## Basic Usage
First, create an empty phase command script by running:
```
generate-mutants --init
```
Replace {instructor-solution} and {hw-name} to specify the file to seed mutants in
and the file to record the generated mutants in.

Then, edit the generated script "mutation_commands.sh" to include the commands
needed for each phase. The `assignment_template` directory an example
of what this could look like for a racket assignment.

Next, generate the mutants with:
```
generate-mutants {instructor-solution}.rkt {hw-name}-mutants.yml
```

And finally run the mutants with:
```
run-mutants --run_tests_in_one_batch {hw-name}-mutants.yml
```

## Dev Setup
Requires python3.10 (with virtual environments) and [editorconfig](https://editorconfig.org/).

After installing python3.10, create a virtual environment and install dependencies:
```
python3.10 -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
python -m pip install pip-tools
pip-sync requirements-dev.txt
```

## Linters
To run pycodestyle, isort, and pyright:
```
./lint.sh
```

## Racket AST and Visitor
AST node classes can be found at the beginning of racket_ast/scheme_reader.py, and visitor classes
are in racket_ast/visitor.py. An example use of the visitor class can be found in read_write_test.py.
The `main` function file reads a file from stdin or the command line, parses the AST (by calling
`racket_ast.scheme_reader.read_file`), and invokes a `ToStrVisitor` on the AST, which prints
the AST back out to stdout (discarding comments and replacing tabs with a single space, but
otherwise preserving the source code structure).
16 changes: 16 additions & 0 deletions assignment_template/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
indent_size = 4

[*.{html,yml,yaml}]
indent_size = 2

# Tab indentation (no size specified)
[Makefile]
indent_style = tab
3 changes: 3 additions & 0 deletions assignment_template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Racket Assignment Template
Contains some scripts to generate an empty Racket assignment in which students have to implement test cases using `check-expect`.
To get started, run `bash init_project.sh {hw_name}`, replacing {hw_name} with the name of the assignment, e.g., "hw3". Then follow the instructions printed by that script.
2 changes: 2 additions & 0 deletions assignment_template/directivestotest
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#lang htdp/bsl
#reader(lib "htdp-beginner-reader.ss" "lang")((modname hw3-master) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f)))
38 changes: 38 additions & 0 deletions assignment_template/init_project.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash

set -e

if [ -z $1 ]; then
echo "Usage: bash $0 hw_name"
exit 1
fi

# The name of the file that students should submit without a file extension.
# e.g. hw1, hw2, etc.
# A new directory with this name will be created, and an assignment template
# will be initialized in that directory using this name where necessary.
hw_name=$1

if [ -e $hw_name ]; then
echo "A file or directory with the name \"$hw_name\" already exists."
echo "Exiting."
exit 1
fi

mkdir $hw_name
cp -r preprocessing $hw_name

for file in template/*; do
sed "s/hwX/$hw_name/g" $file > $hw_name/$(echo $(basename $file) | sed "s/hwX/$hw_name/g")
done


echo "Project initialized. Next steps:"
echo "= Run 'cd $hw_name'"
echo "- Edit reader-directive.txt to contain the reader or lang directive needed for this assignment."
echo "- Add the assignment's public symbols to public-symbols.rkt"
echo "- Run 'racket public-symbols.rkt' and put the printed code at the bottom of $hw_name-instructor-solution.rkt"
echo "- Add your instructor solution and test cases (check-expects) to $hw_name-instructor-solution.rkt"
echo "- Run 'bash extract_instructor_tests.bash' to extract instructor test cases from $hw_name-instructor-solution.rkt into $hw_name-instructor-tests.rkt"
echo "- Run 'bash generate_mutants.bash"
echo "- Run 'make'"
64 changes: 64 additions & 0 deletions assignment_template/preprocessing/extract_check_expects.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#lang racket
(require 2htdp/batch-io)

;; returns the list of objects of parsed file to be written out to file
(define (parse-args file num)
(let
([current_line (read-syntax file file)])
(if (not (eof-object? current_line))
(let [(datum (syntax->datum current_line))]
(if (and (list? datum) (eq? 'check-expect (car datum)))
(begin
(display " (test-case ")
(display "\"Test ")
(display num)
(display " line ")
(display (syntax-line current_line))
(display "\"")
(newline)
(display " ")
(writeln (list 'check-equal? (second datum) (third datum)))
(displayln " )")
(parse-args file (+ 1 num))
)

(parse-args file num)
)
)
'()
)
)
)

(define (main-helper file_name output)
(let ([file (open-input-file file_name)])
(begin
(port-count-lines! file)
(newline)

(displayln "(define test-suite-wrapper" )
(displayln " (test-suite \"Test Suite\"" )
(parse-args file 1)
(displayln " )")
(displayln ")")
(newline)
)
)
)

;;writes each test to a separate line at given location
(define (test-separator lot output_file)
(cond
[(empty? lot) (values)]
[(cons? lot) (begin
(writeln (first lot) output_file)
;;(newline output_file)
(test-separator (rest lot) output_file))])
)

(command-line #:program "Racket check-expect extractor" #:args (input_file)
(begin
(read-accept-reader #t)
(main-helper input_file '())
)
)
28 changes: 28 additions & 0 deletions assignment_template/preprocessing/extract_instructor_tests.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Extract check-expects from the instructor solution into rackunit test cases.
# Prints the resulting code to stdout.
# The extracted tests can be used to evaluate the correctness of student
# implementations.

# The name of the file that students should submit without a file extension.
# e.g. hw1, hw2, etc.
# This name will be interpolated into the file names of the instructor solution
# (e.g. hw1-instructor-solution.rkt), student implementation (e.g. hw1.rkt), and
# instructor test cases (e.g. hw1-instructor-tests.rkt).
hw_name=$1
# The reader or lang special form that should be used in this assignment.
# When check-expects are extracted from the student implementation and written
# to a file containing only test cases, this reader or lang special form will
# be placed at the top of the file.
reader_directive=$2


SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cat <(echo $reader_directive) \
<(echo '(require rackunit)') \
<(echo '(require al2-test-runner)') \
<(echo '(require "./test-runner.rkt")') \
<(echo "(require \"./$hw_name.rkt\")") \
<(racket $SCRIPT_DIR/extract_requires.rkt <(sed -r 's/(#reader.*)|(#lang.*)//' $hw_name-instructor-solution.rkt)) \
<(racket $SCRIPT_DIR/extract_private_defs_instructor.rkt <(sed -r 's/(#reader.*)|(#lang.*)//' $hw_name-instructor-solution.rkt)) \
<(racket $SCRIPT_DIR/extract_check_expects.rkt <(sed -r 's/(#reader.*)|(#lang.*)//' $hw_name-instructor-solution.rkt)) \
<(echo '(test-runner-cmd-line test-suite-wrapper)')
40 changes: 40 additions & 0 deletions assignment_template/preprocessing/extract_private_defs.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#lang racket

(define (extract-private-defs file_name public-def-symbols public-struct-symbols)
(let ([file (open-input-file file_name)] )
(extract-defs-helper file public-def-symbols public-struct-symbols)
)
)

;; returns the list of objects of parsed file to be written out to file
(define (extract-defs-helper file public-def-symbols public-struct-symbols)
(let
([current_line (read-syntax file file)])
(unless (eof-object? current_line)
(let [(datum (syntax->datum current_line))]
(match datum
[
(list (quote define) (var const_name) _) #:when (and (symbol? const_name) (not (member const_name public-def-symbols)))
(writeln datum)
]
[
(list-rest
(quote define)
(list-rest (var func_name) _)
_
) #:when (not (member func_name public-def-symbols))
(writeln datum)
]
[
(list (quote define-struct) (var const_name) _) #:when (and (symbol? const_name) (not (member const_name public-struct-symbols)))
(writeln datum)
]
[_ '()]
)
)
(extract-defs-helper file public-def-symbols public-struct-symbols)
)
)
)

(provide extract-private-defs)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#lang racket

;; To be used in local project setup context (i.e., with preprocessing scripts in a subdirectory).
;; Extracts non-public defs (constants, helper methods, structs) that must accompany
;; the instructor check-expects when extracted from the instructor solution.

(require "./extract_private_defs.rkt")
(require "../public-symbols.rkt")

(command-line #:program "Racket instructor private defs extractor" #:args (input_file)
(begin
(read-accept-reader #t)
(extract-private-defs input_file public-def-symbols public-struct-symbols)
)
)
Loading

0 comments on commit 0d49e38

Please sign in to comment.