diff --git a/.gitignore b/.gitignore
index 19d35dd4..95bd72b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@ obj
*.sln.DotSettings.user
.vs
vendor
-.idea/
+.idea
+*.iml
diff --git a/Java/build.gradle b/Java/build.gradle
index 2c6b41bf..f3773536 100644
--- a/Java/build.gradle
+++ b/Java/build.gradle
@@ -3,13 +3,14 @@ plugins {
}
repositories {
- maven {
- url = 'https://repo.maven.apache.org/maven2'
- }
+ mavenCentral()
}
dependencies {
- testImplementation 'org.junit.jupiter:junit-jupiter:5.5.2'
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2'
+ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.6.2'
+ testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.6.2'
+ testImplementation 'com.approvaltests:approvaltests:5.0.0'
}
group = 'com.gildedrose'
diff --git a/Java/gradle/wrapper/gradle-wrapper.properties b/Java/gradle/wrapper/gradle-wrapper.properties
index 6ce793f2..622ab64a 100644
--- a/Java/gradle/wrapper/gradle-wrapper.properties
+++ b/Java/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/Java/pom.xml b/Java/pom.xml
index 392b3a45..5d65fa0b 100644
--- a/Java/pom.xml
+++ b/Java/pom.xml
@@ -11,8 +11,8 @@
1.8
- 5.5.2
- 2.22.2
+ 5.6.2
+ 3.0.0-M4
diff --git a/README.md b/README.md
index 66e7ea8a..d00d23ff 100644
--- a/README.md
+++ b/README.md
@@ -22,25 +22,29 @@ Whichever testing approach you choose, the idea of the exercise is to do some de
## Text-Based Approval Testing
-This is a testing approach which is very useful when refactoring legacy code. Before you change the code, you run it, and gather the output of the code as a plain text file. You review the text, and if it correctly describes the behaviour as you understand it, you can "approve" it, and save it as a "Golden Master". Then after you change the code, you run it again, and compare the new output against the Golden Master. Any differences, and the test fails.
-
-It's basically the same idea as "assertEquals(expected, actual)" in a unit test, except the text you are comparing is typically much longer, and the "expected" value is saved from actual output, rather than being defined in advance.
-
-Typically a piece of legacy code may not produce suitable textual output from the start, so you may need to modify it before you can write your first text-based approval test. That could involve inserting log statements into the code, or just writing a "main" method that executes the code and prints out what the result is afterwards. It's this latter approach we are using here to test GildedRose.
-
-The Text-Based tests in this repository are designed to be used with the tool "TextTest" (http://texttest.org). This tool helps you to organize and run text-based tests. There is more information in the README file in the "texttests" subdirectory.
+This code comes with comprehensive tests that use this approach. For information about how to run them, see the [texttests README](https://github.com/emilybache/GildedRose-Refactoring-Kata/tree/master/texttests)
## Get going quickly using Cyber-Dojo
-I've also set this kata up on [cyber-dojo](http://cyber-dojo.org) for several languages, so you can get going really quickly:
+I've also set this kata up on [cyber-dojo](https://cyber-dojo.org) for several languages, so you can get going really quickly:
-- [JUnit, Java](http://cyber-dojo.org/forker/fork/751DD02C4C?avatar=snake&tag=8)
-- [C#](http://cyber-dojo.org/forker/fork/5C5AC766B0?avatar=koala&tag=3)
-- [C++](http://cyber-dojo.org/forker/fork/AA86ECBCC9?avatar=rhino&tag=7)
-- [Ruby](http://cyber-dojo.org/forker/fork/A8943EAF92?avatar=hippo&tag=9)
-- [RSpec, Ruby](http://cyber-dojo.org/forker/fork/8E58B0AD16?avatar=raccoon&tag=3)
-- [Python](http://cyber-dojo.org/forker/fork/297041AA7A?avatar=lion&tag=4)
-- [Cucumber, Java](http://cyber-dojo.org/forker/fork/0F82D4BA89?avatar=gorilla&tag=48) - for this one I've also written some step definitions for you
+To create an *individual* exercise:
+- [C#, NUnit](https://cyber-dojo.org/forker/fork_individual/Fz4xFX?index=3)
+- [C++ (g++), GoogleTest](https://cyber-dojo.org/forker/fork_individual/qPPrZy?index=7)
+- [Java, Cucumber](https://cyber-dojo.org/forker/fork_individual/SvUf30?index=2) - for this one I've also written some step definitions for you
+- [Java, JUnit](https://cyber-dojo.org/forker/fork_individual/aJJEN4?index=2)
+- [Python, unittest](https://cyber-dojo.org/forker/fork_individual/NFgFys?index=2)
+- [Ruby, RSpec](https://cyber-dojo.org/forker/fork_individual/D3xbUV?index=3)
+- [Ruby, testunit](https://cyber-dojo.org/forker/fork_individual/zlElgj?index=9)
+
+To create a *group* exercise:
+- [C#, NUnit](https://cyber-dojo.org/forker/fork_group/Fz4xFX?index=3)
+- [C++ (g++), GoogleTest](https://cyber-dojo.org/forker/fork_group/qPPrZy?index=7)
+- [Java, Cucumber](https://cyber-dojo.org/forker/fork_group/SvUf30?index=2) - for this one I've also written some step definitions for you
+- [Java, JUnit](https://cyber-dojo.org/forker/fork_group/aJJEN4?index=2)
+- [Python, unittest](https://cyber-dojo.org/forker/fork_group/NFgFys?index=2)
+- [Ruby, RSpec](https://cyber-dojo.org/forker/fork_group/D3xbUV?index=3)
+- [Ruby, testunit](https://cyber-dojo.org/forker/fork_group/zlElgj?index=9)
## Better Code Hub
diff --git a/cpp-catch2/.gitignore b/cpp-catch2/.gitignore
new file mode 100644
index 00000000..401f2947
--- /dev/null
+++ b/cpp-catch2/.gitignore
@@ -0,0 +1,4 @@
+/build_meson/
+/subprojects/Catch2-*/
+/subprojects/packagecache/
+/cmake-build-*/
diff --git a/cpp-catch2/CMakeLists.txt b/cpp-catch2/CMakeLists.txt
new file mode 100644
index 00000000..4d205699
--- /dev/null
+++ b/cpp-catch2/CMakeLists.txt
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.14..3.16)
+set(CMAKE_VERBOSE_MAKEFILE ON)
+project(GildedRoseKata VERSION 1.0
+ DESCRIPTION "The GildedRose Refactoring kata for an approval testing approach"
+ LANGUAGES CXX)
+include(FetchContent)
+
+FetchContent_Declare(
+ catch2
+ GIT_REPOSITORY https://github.com/catchorg/Catch2.git
+ GIT_TAG v2.12.2
+)
+FetchContent_MakeAvailable(catch2)
+LIST(APPEND CMAKE_MODULE_PATH
+ ${catch2_SOURCE_DIR}/contrib
+ )
+
+FetchContent_Declare(
+ approvaltests_ho
+ URL https://github.com/approvals/ApprovalTests.cpp/releases/download/v.10.0.0/ApprovalTests.v.10.0.0.hpp
+ DOWNLOAD_NO_EXTRACT TRUE
+ DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}/approvaltests
+ DOWNLOAD_NAME ApprovalTests.v.10.0.0.hpp
+)
+FetchContent_GetProperties(approvaltests_ho)
+if (NOT approvaltests_ho_POPULATED)
+ FetchContent_Populate(approvaltests_ho)
+endif ()
+add_library(approvaltests INTERFACE)
+target_include_directories(approvaltests
+ INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/approvaltests
+ INTERFACE ${catch2_SOURCE_DIR}/single_include/catch2
+ )
+
+add_executable(gildedrose_catch2
+ src/GildedRose.h
+ src/GildedRose.cc
+ test/gildedrose_catch.cpp
+ test/main.cpp)
+set_target_properties(gildedrose_catch2 PROPERTIES CXX_STANDARD 11)
+target_include_directories(gildedrose_catch2
+ PUBLIC src)
+target_link_libraries(gildedrose_catch2 Catch2::Catch2 approvaltests)
+
+include(CTest)
+include(ParseAndAddCatchTests)
+ParseAndAddCatchTests(gildedrose_catch2)
\ No newline at end of file
diff --git a/cpp-catch2/README.md b/cpp-catch2/README.md
new file mode 100644
index 00000000..66b941cb
--- /dev/null
+++ b/cpp-catch2/README.md
@@ -0,0 +1,20 @@
+C++ version of Gilded Rose with Catch 2 and Approvals
+======================================================
+
+This is a C++ start of the ApprovalTest version of the Gilded Rose Refactoring Kata. See
+the [top level readme](https://github.com/emilybache/GildedRose-Refactoring-Kata)
+ for a general description of the exercise.
+
+
+CMake
+-----
+
+CMake is included in CLion from JetBrains. Without CMake files
+CLion has a hard time to handle c-projects.
+
+To install CMake (if you don't use CLion) on macOS using brew
+
+ brew install cmake
+
+Tested on CMake 3.15.3 (included with CLion 2019.3) on macOS
+
diff --git a/cpp-catch2/src/GildedRose.cc b/cpp-catch2/src/GildedRose.cc
new file mode 100644
index 00000000..8df23e47
--- /dev/null
+++ b/cpp-catch2/src/GildedRose.cc
@@ -0,0 +1,80 @@
+#include "GildedRose.h"
+
+GildedRose::GildedRose(vector- & items) : items(items)
+{}
+
+void GildedRose::updateQuality()
+{
+ for (int i = 0; i < items.size(); i++)
+ {
+ if (items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert")
+ {
+ if (items[i].quality > 0)
+ {
+ if (items[i].name != "Sulfuras, Hand of Ragnaros")
+ {
+ items[i].quality = items[i].quality - 1;
+ }
+ }
+ }
+ else
+ {
+ if (items[i].quality < 50)
+ {
+ items[i].quality = items[i].quality + 1;
+
+ if (items[i].name == "Backstage passes to a TAFKAL80ETC concert")
+ {
+ if (items[i].sellIn < 11)
+ {
+ if (items[i].quality < 50)
+ {
+ items[i].quality = items[i].quality + 1;
+ }
+ }
+
+ if (items[i].sellIn < 6)
+ {
+ if (items[i].quality < 50)
+ {
+ items[i].quality = items[i].quality + 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (items[i].name != "Sulfuras, Hand of Ragnaros")
+ {
+ items[i].sellIn = items[i].sellIn - 1;
+ }
+
+ if (items[i].sellIn < 0)
+ {
+ if (items[i].name != "Aged Brie")
+ {
+ if (items[i].name != "Backstage passes to a TAFKAL80ETC concert")
+ {
+ if (items[i].quality > 0)
+ {
+ if (items[i].name != "Sulfuras, Hand of Ragnaros")
+ {
+ items[i].quality = items[i].quality - 1;
+ }
+ }
+ }
+ else
+ {
+ items[i].quality = items[i].quality - items[i].quality;
+ }
+ }
+ else
+ {
+ if (items[i].quality < 50)
+ {
+ items[i].quality = items[i].quality + 1;
+ }
+ }
+ }
+ }
+}
diff --git a/cpp-catch2/src/GildedRose.h b/cpp-catch2/src/GildedRose.h
new file mode 100644
index 00000000..8464f87b
--- /dev/null
+++ b/cpp-catch2/src/GildedRose.h
@@ -0,0 +1,24 @@
+#include
+#include
+
+using namespace std;
+
+class Item
+{
+public:
+ string name;
+ int sellIn;
+ int quality;
+ Item(string name, int sellIn, int quality) : name(name), sellIn(sellIn), quality(quality)
+ {}
+};
+
+class GildedRose
+{
+public:
+ vector
- & items;
+ GildedRose(vector
- & items);
+
+ void updateQuality();
+};
+
diff --git a/cpp-catch2/test/ApprovalTests.hpp b/cpp-catch2/test/ApprovalTests.hpp
new file mode 100644
index 00000000..6da10acd
--- /dev/null
+++ b/cpp-catch2/test/ApprovalTests.hpp
@@ -0,0 +1 @@
+#include "ApprovalTests.v.10.0.0.hpp"
\ No newline at end of file
diff --git a/cpp-catch2/test/gildedrose_catch.cpp b/cpp-catch2/test/gildedrose_catch.cpp
new file mode 100644
index 00000000..753b153b
--- /dev/null
+++ b/cpp-catch2/test/gildedrose_catch.cpp
@@ -0,0 +1,21 @@
+#include
+#include "ApprovalTests.hpp"
+
+#include "GildedRose.h"
+
+std::ostream& operator<<(std::ostream& os, const Item& obj)
+{
+ return os
+ << "name: " << obj.name
+ << ", sellIn: " << obj.sellIn
+ << ", quality: " << obj.quality;
+}
+
+TEST_CASE("UpdateQuality") {
+
+ vector
- items;
+ items.push_back(Item("foo", 0, 0));
+ GildedRose app(items);
+ app.updateQuality();
+ REQUIRE("fixme" == app.items[0].name);
+}
diff --git a/cpp-catch2/test/main.cpp b/cpp-catch2/test/main.cpp
new file mode 100644
index 00000000..94bae37b
--- /dev/null
+++ b/cpp-catch2/test/main.cpp
@@ -0,0 +1,5 @@
+#define CATCH_CONFIG_MAIN
+#define APPROVALS_CATCH
+
+#include "catch2/catch.hpp"
+#include "ApprovalTests.hpp"
\ No newline at end of file
diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt
index 65020b89..bd89b333 100644
--- a/cpp/test/CMakeLists.txt
+++ b/cpp/test/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory(cpp_catch2_approvaltest)
add_subdirectory(cpp_catch2_unittest)
add_subdirectory(cpp_googletest_approvaltest)
add_subdirectory(cpp_googletest_unittest)
+add_subdirectory(cpp_texttest)
diff --git a/cpp/test/cpp_texttest/CMakeLists.txt b/cpp/test/cpp_texttest/CMakeLists.txt
new file mode 100644
index 00000000..d9eb71ea
--- /dev/null
+++ b/cpp/test/cpp_texttest/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(TEST_NAME GildedRoseTextTests)
+add_executable(${TEST_NAME} GildedRoseTextTests.cc)
+target_sources(${TEST_NAME} PRIVATE GildedRoseTextTests.cc)
+target_link_libraries(${TEST_NAME} lib src)
+set_property(TARGET ${TEST_NAME} PROPERTY CXX_STANDARD 11)
+add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
+
+# Set compiler option /FC for Visual Studio to to make the __FILE__ macro expand to full path.
+# The __FILE__ macro is used by Catch2 to get the path to current test file.
+# Links:
+# * https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019
+# * https://docs.microsoft.com/en-us/cpp/build/reference/fc-full-path-of-source-code-file-in-diagnostics?view=vs-2019
+if (MSVC)
+ target_compile_options(${TEST_NAME} PRIVATE "/FC")
+endif()
diff --git a/cpp/test/cpp_texttest/GildedRoseTextTests.cc b/cpp/test/cpp_texttest/GildedRoseTextTests.cc
new file mode 100644
index 00000000..e47f1058
--- /dev/null
+++ b/cpp/test/cpp_texttest/GildedRoseTextTests.cc
@@ -0,0 +1,44 @@
+#include
+#include "GildedRose.h"
+
+int
+print_item(Item *item)
+{
+ return printf("%s, %d, %d\n", item->name.c_str(), item->sellIn, item->quality);
+}
+
+int main()
+{
+ vector
- items;
+
+ items.emplace_back("+5 Dexterity Vest", 10, 20);
+ items.emplace_back("Aged Brie", 2, 0);
+ items.emplace_back("Elixir of the Mongoose", 5, 7);
+ items.emplace_back("Sulfuras, Hand of Ragnaros", 0, 80);
+ items.emplace_back("Sulfuras, Hand of Ragnaros", -1, 80);
+ items.emplace_back("Backstage passes to a TAFKAL80ETC concert", 15, 20);
+ items.emplace_back("Backstage passes to a TAFKAL80ETC concert", 10, 49);
+ items.emplace_back("Backstage passes to a TAFKAL80ETC concert", 5, 49);
+
+ // this Conjured item doesn't yet work properly
+ items.emplace_back("Conjured Mana Cake", 3, 6);
+
+ puts("OMGHAI!");
+
+ GildedRose app(items);
+
+ for (int day = 0; day <= 30; day++)
+ {
+ printf("-------- day %d --------\n", day);
+ printf("name, sellIn, quality\n");
+ for (auto & item : items)
+ {
+ print_item(&item);
+ }
+ printf("\n");
+ app.updateQuality();
+ }
+ return 0;
+}
+
+
diff --git a/plpgsql/Dockerfile b/plpgsql/Dockerfile
new file mode 100644
index 00000000..d0f42b3b
--- /dev/null
+++ b/plpgsql/Dockerfile
@@ -0,0 +1,45 @@
+FROM postgres:12.1 as base
+WORKDIR /app
+
+ENV PGHOST=localhost
+ENV PGDATABASE=kata
+ENV PGPASSWORD=admin
+ENV PGUSER=postgres
+ENV POSTGRES_PASSWORD=admin
+ENV PGDATA /var/lib/postgresql/data_local
+
+RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA"
+
+ADD ./*.sh /app/
+ADD ./src/item.sql /app/src/
+ADD ./src/new_item.sql /app/src/
+
+# PGUNIT
+FROM base as pgunit
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates wget \
+ && rm -rf /var/lib/apt/lists/*
+
+ADD ./pgunit/initialize.sh /app/
+ADD ./pgunit/*.sql /app/
+RUN chmod +x ./*.sh \
+ && ./initializeDocker.sh
+
+# PGTAP
+FROM base as pgtap
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates build-essential git-core libv8-dev curl postgresql-server-dev-12 \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN mkdir -p /tmp/pgtap \
+ && cd /tmp/pgtap \
+ && git clone https://github.com/theory/pgtap.git /tmp/pgtap \
+ && make \
+ && make install \
+ && cpan TAP::Parser::SourceHandler::pgTAP
+
+ADD ./pgtap/initialize.sh /app/
+RUN chmod +x ./*.sh \
+ && ./initializeDocker.sh
diff --git a/plpgsql/README.md b/plpgsql/README.md
index 4ba245c2..93337289 100644
--- a/plpgsql/README.md
+++ b/plpgsql/README.md
@@ -6,36 +6,58 @@ You'll need:
To use remote / local dockerized database, add ``` --host --port --username``` parameters to plsql invocation.
# Setup
+## With docker
+Run `docker-compose up -d ` to start, and `docker-compose exec bash` to enter in container.
+`` is the testing framework name. Two values are possible: `pgunit` or `pgtap`
+
+## Without docker
In shell:
-- create database: ```createdb gilded_rose```
-- create item table (structure): ```psql -d gilded_rose -f ./structure/create.sql```
-- load code into database: ```psql -d gilded_rose -f ./src/update_quality.sql ```
+- create database: ```createdb kata```
+- create item table (structure): ```psql -d kata -f ./src/item.sql```
+- create procedure to help to add item: ```psql -d kata -f ./src/new_item.sql```
+- load code into database: ```psql -d kata -f ./src/update_quality.sql ```
If you get this message```LINE 1: CREATE OR REPLACE PROCEDURE public.update_quality()```, your PostgreSQL version may under 11, consider upgrading.
-# Run
+# Run
In shell:
-- load manual test data into database: ```psql -d gilded_rose -f ./test/manual/load.sql```
-- connect to CLI: ```psql -d gilded_rose```
+- connect to CLI: ```psql -d kata```
+- add item: ```CALL new_item('+5 Dexterity Vest', 10, 20);```
- check item state: ```SELECT * FROM item;```
- execute item update: ```CALL update_quality();```
- check item state: ```SELECT * FROM item;```
- empty table : ```TRUNCATE TABLE item;```
+# Kata
+`src/update_quality.sql` contains code to refactor.
# Test
## Using pgTAP
-
### Requirements
-Install pgTAP [instructions here](https://pgtap.org/documentation.html#installation)
+Install pgTAP [instructions here](https://pgtap.org/documentation.html#installation)
+It's already installed with docker
```item``` table is supposed to be empty.
If not, it would cause a (false positive)[https://en.wikipedia.org/wiki/False_positives_and_false_negatives]
### Execute
-In shell, execute ```pg_prove --dbname gilded_rose test/pgtap/*.sql```.
-You should get ```test/pgtap/template.sql .. ok All tests successful.```
+Run `docker-compose up -d pgtap` to start, and `docker-compose exec pgtap bash` to enter in container.
+In shell, execute ```psql -d kata -f src/update_quality.sql && pg_prove pgtap/test_*.sql```.
+You should get ```pgtap/test_case_update_quality.sql .. ok All tests successful.```
If you get this message ```ERROR: function plan(integer) does not exist LINE 1: SELECT PLAN(1);```, pgTAP is not working => check your pgTAP installation.
If you get this message ```Failed test: 2 Parse errors: Bad plan. You planned 1 tests but ran 2.```, the item table contains data, interfering with the test => empty it, then run test again.
+
+`pgtap/test_case_update_quality.sql` contains test examples.
+
+## Using pgunit
+### Requirement
+Unit test framework used : pgunit (https://github.com/adrianandrei-ca/pgunit)
+It's already installed with docker
+
+### Execute
+Run `docker-compose up -d pgunit` to start, and `docker-compose exec pgunit bash` to enter in container.
+You can run `cat src/update_quality.sql pgunit/run_tests.sql | psql -d kata -f -`
+
+`pgunit/run_tests.sql` contains test examples.
diff --git a/plpgsql/docker-compose.yml b/plpgsql/docker-compose.yml
new file mode 100644
index 00000000..b753b164
--- /dev/null
+++ b/plpgsql/docker-compose.yml
@@ -0,0 +1,22 @@
+version: '3.4'
+
+services:
+ pgunit:
+ # image: fpellet/gildedrose-refactoring-kata:pgunit
+ build:
+ context: .
+ target: pgunit
+ ports:
+ - "5432:5432"
+ volumes:
+ - .:/app/:z
+
+ pgtap:
+ # image: fpellet/gildedrose-refactoring-kata:pgtap
+ build:
+ context: .
+ target: pgtap
+ ports:
+ - "5432:5432"
+ volumes:
+ - .:/app/:z
diff --git a/plpgsql/initializeDatabase.sh b/plpgsql/initializeDatabase.sh
new file mode 100644
index 00000000..09b6202a
--- /dev/null
+++ b/plpgsql/initializeDatabase.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -ex
+
+echo "Create database"
+psql -d postgres -c 'DROP DATABASE IF EXISTS kata;'
+psql -d postgres -c 'CREATE DATABASE kata;'
+
+./initialize.sh
+
+echo "Add current code"
+psql -d kata -f src/item.sql
+psql -d kata -f src/new_item.sql
diff --git a/plpgsql/pgunit/initializeDocker.sh b/plpgsql/initializeDocker.sh
similarity index 100%
rename from plpgsql/pgunit/initializeDocker.sh
rename to plpgsql/initializeDocker.sh
diff --git a/plpgsql/pgtap/initialize.sh b/plpgsql/pgtap/initialize.sh
new file mode 100644
index 00000000..7646180d
--- /dev/null
+++ b/plpgsql/pgtap/initialize.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -ex
+
+echo "Enable extension"
+psql -d kata -c 'CREATE EXTENSION IF NOT EXISTS pgtap;'
diff --git a/plpgsql/pgtap/test_case_update_quality.sql b/plpgsql/pgtap/test_case_update_quality.sql
new file mode 100644
index 00000000..5d06a167
--- /dev/null
+++ b/plpgsql/pgtap/test_case_update_quality.sql
@@ -0,0 +1,18 @@
+BEGIN;
+-- Plan count should match the number of tests. If it does not then pg_prove will fail the test
+SELECT plan(1);
+
+-- Run the tests.
+-- Given
+TRUNCATE TABLE item;
+CALL new_item('foo', 0, 0);
+
+-- When
+CALL update_quality();
+
+-- Then
+SELECT is( name, 'fixme', 'name did change' ) FROM item;
+
+-- Finish the tests and clean up.
+SELECT * FROM finish();
+ROLLBACK;
diff --git a/plpgsql/pgunit/Dockerfile b/plpgsql/pgunit/Dockerfile
deleted file mode 100644
index 4c3cc347..00000000
--- a/plpgsql/pgunit/Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-FROM postgres:12.1
-WORKDIR /app
-
-ENV PGHOST=localhost
-ENV PGDATABASE=kata
-ENV PGPASSWORD=admin
-ENV PGUSER=postgres
-ENV POSTGRES_PASSWORD=admin
-ENV PGDATA /var/lib/postgresql/data_local
-
-RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA"
-
-RUN apt-get update \
- && apt-get install -y --no-install-recommends ca-certificates wget \
- && rm -rf /var/lib/apt/lists/*
-
-ADD ./*.sh /app/
-ADD ./*.sql /app/
-RUN chmod +x ./*.sh \
- && ./initializeDocker.sh
diff --git a/plpgsql/pgunit/docker-compose.yml b/plpgsql/pgunit/docker-compose.yml
deleted file mode 100644
index 60183e85..00000000
--- a/plpgsql/pgunit/docker-compose.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-version: '3'
-
-services:
- database:
- build: .
- ports:
- - "5432:5432"
- volumes:
- - .:/app/:z
-
- admin:
- image: adminer
- links:
- - database
- ports:
- - "8081:8080"
diff --git a/plpgsql/pgunit/initializeDatabase.sh b/plpgsql/pgunit/initialize.sh
similarity index 59%
rename from plpgsql/pgunit/initializeDatabase.sh
rename to plpgsql/pgunit/initialize.sh
index 12b1d33d..60557019 100644
--- a/plpgsql/pgunit/initializeDatabase.sh
+++ b/plpgsql/pgunit/initialize.sh
@@ -2,9 +2,7 @@
set -ex
-echo "Create database"
-psql -d postgres -c 'DROP DATABASE IF EXISTS kata;'
-psql -d postgres -c 'CREATE DATABASE kata;'
+echo "Enable DBLINK"
psql -d kata -c 'CREATE EXTENSION DBLINK;'
echo "Initialize test framework"
@@ -14,8 +12,3 @@ wget https://raw.githubusercontent.com/adrianandrei-ca/pgunit/bc69dfc526ec3db55f
echo "Initialize custom asserts"
psql -d kata -f asserts.sql
-
-echo "Add current code"
-psql -d kata -f item.sql
-psql -d kata -f new_item.sql
-psql -d kata -f update_quality.sql
diff --git a/plpgsql/pgunit/readme.md b/plpgsql/pgunit/readme.md
deleted file mode 100644
index 6421ed1c..00000000
--- a/plpgsql/pgunit/readme.md
+++ /dev/null
@@ -1,10 +0,0 @@
-## Requirement
-Testing on postgres 12
-Unit test framework used : pgunit (https://github.com/adrianandrei-ca/pgunit)
-
-## Setup
-Run `docker-compose up -d` to start, and `docker-compose exec database bash` to enter in container.
-You can run `cat update_quality.sql run_tests.sql | psql -d kata -f -`
-
-## Kata
-`update_quality.sql` contains code to refactor, and `run_tests.sql` contains test examples.
diff --git a/plpgsql/pgunit/item.sql b/plpgsql/src/item.sql
similarity index 100%
rename from plpgsql/pgunit/item.sql
rename to plpgsql/src/item.sql
diff --git a/plpgsql/pgunit/new_item.sql b/plpgsql/src/new_item.sql
similarity index 100%
rename from plpgsql/pgunit/new_item.sql
rename to plpgsql/src/new_item.sql
diff --git a/plpgsql/pgunit/update_quality.sql b/plpgsql/src/update_quality.sql
similarity index 100%
rename from plpgsql/pgunit/update_quality.sql
rename to plpgsql/src/update_quality.sql
diff --git a/plpgsql/structure/create.sql b/plpgsql/structure/create.sql
deleted file mode 100644
index 263b860d..00000000
--- a/plpgsql/structure/create.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-CREATE TABLE item (
- name CHARACTER VARYING(100) NOT NULL,
- sellIn INTEGER,
- quality INTEGER NOT NULL
-);
diff --git a/ruby/.gitignore b/ruby/.gitignore
new file mode 100644
index 00000000..c38fa4e0
--- /dev/null
+++ b/ruby/.gitignore
@@ -0,0 +1,2 @@
+.idea
+*.iml
diff --git a/texttests/README.md b/texttests/README.md
index 7f8a53ca..4213a0fc 100644
--- a/texttests/README.md
+++ b/texttests/README.md
@@ -1,24 +1,46 @@
# TextTest regression tests
-This folder contains Text-Based tests for the GildedRose Refactoring Kata.
+This folder contains Text-Based Approval tests for the GildedRose Refactoring Kata. They are fairly comprehensive and well worth using if you'd prefer to go straight to the refactoring without writing your own tests first.
-These tests are designed to be used with the open source testing tool "TextTest", available from http://texttest.org You can run them without it too though, see below.
+These tests are designed to be used with the open source testing tool "TextTest", available from [http://texttest.org](http://texttest.org).
+
+## Install TextTest
+
+There are install instructions on the [texttests website](http://texttest.sourceforge.net/index.php?page=documentation_4_0&n=install_texttest). If you are happy to run without the Graphical User Interface, then you only need python3 and pip:
+
+ > pip install texttest
+
+## Configure language version
+
+Before you can run the tests you need to tell texttest which language version of GildedRose you plan to refactor. Open the file 'config.gr' and edit it. Several languages are supported. All lines starting with '#' are comments in this file. Find the lines referring to the language you want, and uncomment them. (Note some languages like Java need several lines uncommented)
+
+While you're here, change the settings for editor and diff program to match your preferences. By default it uses 'subl' and 'meld'. It will accept any editors or diff programs that you can run from the command line.
+
+## running TextTest
+
+Start texttest from the folder above the one this file is in. Texttest detects the current working directory and uses that as the variable $TEXTTEST_HOME in the config.gr file.
+
+ # replace this path with wherever you cloned this repo
+ > cd /home/ec2-user/workspace/GildedRose-Refactoring-Kata
+ > texttest &
+
+This should start the GUI for the TextTest tool. Select the test case "ThirtyDays" and press the "Run" button. This will open a new 'runner' window for each test run.
+
+If the texttest GUI doesn't work, or you prefer to use the command line, use this instead:
+
+ > texttest -con
+
+That will run all the test cases it finds and report the results.
## Running without TextTest
This should be perfectly possible, but is probably less convenient than using TextTest.
-Write a script that will execute the SUT (see "config.gr" for details of the executables), giving the commandline options listed in "options.gr". Collect the output from standard output in a file, and diff that against the golden copy "stdout.gr". Any diff is a test failure.
+Write a script that will execute the system under test (see "config.gr" for details of the executables), giving the commandline options listed in "options.gr". Collect the output from standard output in a file, and diff that against the golden copy "stdout.gr". Any diff is a test failure.
-## Running with TextTest
+## Explaining TextTest test cases
-- Install TextTest (see http://texttest.org)
-- set $TEXTTEST_HOME environment variable to point at the "texttests" folder
-- run texttest using a command like "python texttest.py -a gr"
-
-This should start the GUI for the TextTest tool.
-
-Each test case has it's own subdirectory. The name of the directory is the name of the test - in this case "ThirtyDays". The "Golden Copy" of the output for that test case is kept in that directory. In this case we have three files:
+Each test case has it's own subdirectory. The name of the directory is the name of the test - in this case "ThirtyDays". The "Golden Master" of the output for that test case is kept in that directory. In this case we have three files:
- __stderr.gr__ - the expected output to Standard Error (stderr)
- __stdout.gr__ - the expected output to Standard Output (stdout)
@@ -34,4 +56,11 @@ To run a test, click on it in the GUI and select "Run". TextTest will run it in
If you run into difficulties with TextTest, there is documentation available on [texttest.org](http://texttest.org), or you can ask a question on the [mailing list](https://lists.sourceforge.net/lists/listinfo/texttest-users).
+## Introduction to Text-Based Approval Testing
+
+This is a testing approach which is very useful when refactoring legacy code. Before you change the code, you run it, and gather the output of the code as a plain text file. You review the text, and if it correctly describes the behaviour as you understand it, you can "approve" it, and save it as a "Golden Master". Then after you change the code, you run it again, and compare the new output against the Golden Master. Any differences, and the test fails.
+
+It's basically the same idea as "assertEquals(expected, actual)" in a unit test, except the text you are comparing is typically much longer, and the "expected" value is saved from actual output, rather than being defined in advance.
+
+Typically a piece of legacy code may not produce suitable textual output from the start, so you may need to modify it before you can write your first text-based approval test. One way to do that is to write a "main" method that executes the code and prints out what the result is afterwards. Each language version has implemented a texttest 'fixture' that does this. It runs the GildedRose 'update_quality' method once each day for 30 days, printing the item state each day.
diff --git a/texttests/config.gr b/texttests/config.gr
index 5be96e39..d043c270 100755
--- a/texttests/config.gr
+++ b/texttests/config.gr
@@ -1,35 +1,31 @@
full_name:Gilded Rose Refactoring Kata
-# location where you have your clone
-default_checkout:/Users/emily/training_materials/Refactoring-Katas/GildedRose
-
-# Settings for the Java version
-executable:com.gildedrose.TexttestFixture
-interpreter:java
-# note you'll also need to update the file environment.gr with your classpath if you keep your classfiles somewhere unusual
+# set your preferred editor and diff tool.
+view_program:subl
+diff_program:meld
# Settings for the Python version
-#executable:${TEXTTEST_CHECKOUT}/python/texttest_fixture.py
+#executable:${TEXTTEST_HOME}/python/texttest_fixture.py
#interpreter:python
-# Settings for the C++ version
-#executable:${TEXTTEST_CHECKOUT}/cpp/GildedRoseTextTests
+# Settings for the cpp version
+#executable:${TEXTTEST_HOME}/cpp/cmake-build-debug/test/cpp_texttest/GildedRoseTextTests
+
+# Settings for the Java version
+#executable:com.gildedrose.TexttestFixture
+#interpreter:java
+# note you'll also need to update the file environment.gr with your classpath if you keep your classfiles somewhere unusual
# Settings for the Ruby version
-#executable:${TEXTTEST_CHECKOUT}/ruby/texttest_fixture.rb
+#executable:${TEXTTEST_HOME}/ruby/texttest_fixture.rb
#interpreter:ruby
# Settings for the C# version
-#executable:${TEXTTEST_CHECKOUT}/GildedRose.exe
+#executable:${TEXTTEST_HOME}/GildedRose.exe
# Settings for the Perl version
-#executable:${TEXTTEST_CHECKOUT}/perl/texttest_fixture.pl
+#executable:${TEXTTEST_HOME}/perl/texttest_fixture.pl
#interpreter:perl
-# turn on one of these if you prefer them to notepad or emacs.
-[view_program]
-*:mate
-#*:gedit
-[end]
filename_convention_scheme:standard
diff --git a/texttests/environment.gr b/texttests/environment.gr
index 1483a513..4e03182a 100755
--- a/texttests/environment.gr
+++ b/texttests/environment.gr
@@ -1,3 +1,3 @@
# If your .class files are somewhere else, add the path to the list
-CLASSPATH:${TEXTTEST_CHECKOUT}/Java:${TEXTTEST_CHECKOUT}/Java/bin
-PERL5OPT:-I${TEXTTEST_CHECKOUT}/perl
+CLASSPATH:${TEXTTEST_HOME}/Java:${TEXTTEST_HOME}/Java/bin
+PERL5OPT:-I${TEXTTEST_HOME}/perl
\ No newline at end of file