Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/auto-sync.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ scrabble-score
secret-handshake
series
sieve
simple-cipher
space-age
spiral-matrix
square-root
Expand Down
2 changes: 1 addition & 1 deletion exercises/practice/simple-cipher/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Description
# Instructions

Create an implementation of the [Vigenère cipher][wiki].
The Vigenère cipher is a simple substitution cipher.
Expand Down
7 changes: 5 additions & 2 deletions exercises/practice/simple-cipher/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"authors": [
"camilopayan"
"camilopayan",
"Narkunan"
],
"contributors": [
"MichaelBunker"
Expand All @@ -16,5 +17,7 @@
".meta/example.php"
]
},
"blurb": "Implement a simple shift cipher like Caesar and a more secure substitution cipher"
"blurb": "Implement the Vigenère cipher, a simple substitution cipher.",
"source": "Substitution Cipher at Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Substitution_cipher"
}
24 changes: 0 additions & 24 deletions exercises/practice/simple-cipher/.meta/example.php
Original file line number Diff line number Diff line change
@@ -1,29 +1,5 @@
<?php

/*
* By adding type hints and enabling strict type checking, code can become
* easier to read, self-documenting and reduce the number of potential bugs.
* By default, type declarations are non-strict, which means they will attempt
* to change the original type to match the type specified by the
* type-declaration.
*
* In other words, if you pass a string to a function requiring a float,
* it will attempt to convert the string value to a float.
*
* To enable strict mode, a single declare directive must be placed at the top
* of the file.
* This means that the strictness of typing is configured on a per-file basis.
* This directive not only affects the type declarations of parameters, but also
* a function's return type.
*
* For more info review the Concept on strict type checking in the PHP track
* <link>.
*
* To disable strict typing, comment out the directive below.
*/

declare(strict_types=1);

class SimpleCipher
{
public const LETTERS = "abcdefghijklmnopqrstuvwxyz";
Expand Down
46 changes: 46 additions & 0 deletions exercises/practice/simple-cipher/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[b8bdfbe1-bea3-41bb-a999-b41403f2b15d]
description = "Random key cipher -> Can encode"

[3dff7f36-75db-46b4-ab70-644b3f38b81c]
description = "Random key cipher -> Can decode"

[8143c684-6df6-46ba-bd1f-dea8fcb5d265]
description = "Random key cipher -> Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method"

[defc0050-e87d-4840-85e4-51a1ab9dd6aa]
description = "Random key cipher -> Key is made only of lowercase letters"

[565e5158-5b3b-41dd-b99d-33b9f413c39f]
description = "Substitution cipher -> Can encode"

[d44e4f6a-b8af-4e90-9d08-fd407e31e67b]
description = "Substitution cipher -> Can decode"

[70a16473-7339-43df-902d-93408c69e9d1]
description = "Substitution cipher -> Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method"

[69a1458b-92a6-433a-a02d-7beac3ea91f9]
description = "Substitution cipher -> Can double shift encode"

[21d207c1-98de-40aa-994f-86197ae230fb]
description = "Substitution cipher -> Can wrap on encode"

[a3d7a4d7-24a9-4de6-bdc4-a6614ced0cb3]
description = "Substitution cipher -> Can wrap on decode"

[e31c9b8c-8eb6-45c9-a4b5-8344a36b9641]
description = "Substitution cipher -> Can encode messages longer than the key"

[93cfaae0-17da-4627-9a04-d6d1e1be52e3]
description = "Substitution cipher -> Can decode messages longer than the key"
129 changes: 66 additions & 63 deletions exercises/practice/simple-cipher/SimpleCipherTest.php
Original file line number Diff line number Diff line change
@@ -1,29 +1,8 @@
<?php

/*
* By adding type hints and enabling strict type checking, code can become
* easier to read, self-documenting and reduce the number of potential bugs.
* By default, type declarations are non-strict, which means they will attempt
* to change the original type to match the type specified by the
* type-declaration.
*
* In other words, if you pass a string to a function requiring a float,
* it will attempt to convert the string value to a float.
*
* To enable strict mode, a single declare directive must be placed at the top
* of the file.
* This means that the strictness of typing is configured on a per-file basis.
* This directive not only affects the type declarations of parameters, but also
* a function's return type.
*
* For more info review the Concept on strict type checking in the PHP track
* <link>.
*
* To disable strict typing, comment out the directive below.
*/

declare(strict_types=1);

use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;

class SimpleCipherTest extends TestCase
Expand All @@ -33,62 +12,57 @@ public static function setUpBeforeClass(): void
require_once 'SimpleCipher.php';
}

public function testRandomCipherKeyIsLetters(): void
{
$cipher = new SimpleCipher();
$this->assertMatchesRegularExpression('/\A[a-z]+\z/', $cipher->key);
}

/**
* Here we take advantage of the fact that plaintext of "aaa..." doesn't
* output the key. This is a critical problem with shift ciphers, some
* characters will always output the key verbatim.
*
* Uuid: b8bdfbe1-bea3-41bb-a999-b41403f2b15d.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not add a dot at the end of the UUIDs:

Suggested change
* Uuid: b8bdfbe1-bea3-41bb-a999-b41403f2b15d.
* Uuid: b8bdfbe1-bea3-41bb-a999-b41403f2b15d

*/
#[TestDox('Random key cipher -> Can encode')]
public function testRandomKeyCipherEncode(): void

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please adjust the method names to match the TestDox sentence.

Suggested change
public function testRandomKeyCipherEncode(): void
public function testRandomKeyCipherCanEncode(): void

{
$cipher = new SimpleCipher();
$plaintext = 'aaaaaaaaaa';
$this->assertEquals(substr($cipher->key, 0, 10), $cipher->encode($plaintext));
}

/**
* Uuid: 3dff7f36-75db-46b4-ab70-644b3f38b81c.
*/
Comment on lines +30 to +32

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* Uuid: 3dff7f36-75db-46b4-ab70-644b3f38b81c.
*/
/**
* Uuid: 3dff7f36-75db-46b4-ab70-644b3f38b81c
*/

#[TestDox('Random key cipher -> Can decode')]
public function testRandomKeyCipherDecode(): void
{
$cipher = new SimpleCipher();
$plaintext = 'aaaaaaaaaa';
$this->assertEquals($plaintext, $cipher->decode(substr($cipher->key, 0, 10)));
}

/**
* Uuid: 8143c684-6df6-46ba-bd1f-dea8fcb5d265.
*/
#[TestDox('Random key cipher -> Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method')]
public function testRandomKeyCipherReversible(): void
Comment on lines +41 to 45

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a real special case. The example should not be in the TestDox.

Suggested change
/**
* Uuid: 8143c684-6df6-46ba-bd1f-dea8fcb5d265.
*/
#[TestDox('Random key cipher -> Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method')]
public function testRandomKeyCipherReversible(): void
/**
* Uuid: 8143c684-6df6-46ba-bd1f-dea8fcb5d265.
*/
#[TestDox('Random key cipher -> Is reversible')]
public function testRandomKeyCipherReversible(): void

{
$cipher = new SimpleCipher();
$plaintext = 'abcdefghij';
$this->assertEquals($plaintext, $cipher->decode($cipher->encode($plaintext)));
}

public function testCipherWithCapsKey(): void
{
$this->expectException(InvalidArgumentException::class);
$cipher = new SimpleCipher('ABCDEF');
}

public function testCipherWithNumericKey(): void
{
$this->expectException(InvalidArgumentException::class);
$cipher = new SimpleCipher('12345');
}

public function testCipherWithEmptyKey(): void
{
$this->expectException(InvalidArgumentException::class);
$cipher = new SimpleCipher('');
}

public function testCipherKeyIsAsSubmitted(): void
/**
* Uuid: defc0050-e87d-4840-85e4-51a1ab9dd6aa.
*/
Comment on lines +52 to +54

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please go through all DocBlocks and fix the indentation. 4 spaces on the comment starting line, then 5 spaces until the comment ends. That's the rule. And no dot after the UUID.

Suggested change
/**
* Uuid: defc0050-e87d-4840-85e4-51a1ab9dd6aa.
*/
/**
* Uuid: defc0050-e87d-4840-85e4-51a1ab9dd6aa
*/

#[TestDox('Random key cipher -> Key is made only of lowercase letters')]
public function testRandomCipherKeyIsLetters(): void
{
$cipher = new SimpleCipher('abcdefghij');
$this->assertEquals($cipher->key, 'abcdefghij');
$cipher = new SimpleCipher();
$this->assertMatchesRegularExpression('/\A[a-z]+\z/', $cipher->key);
}

/**
* Uuid: 565e5158-5b3b-41dd-b99d-33b9f413c39f.
*/
#[TestDox('Substitution cipher -> Can encode')]
public function testCipherEncode(): void
{
$cipher = new SimpleCipher('abcdefghij');
Expand All @@ -97,6 +71,10 @@ public function testCipherEncode(): void
$this->assertEquals($ciphertext, $cipher->encode($plaintext));
}

/**
* Uuid: d44e4f6a-b8af-4e90-9d08-fd407e31e67b.
*/
#[TestDox('Substitution cipher -> Can decode')]
public function testCipherDecode(): void
{
$cipher = new SimpleCipher('abcdefghij');
Expand All @@ -105,13 +83,21 @@ public function testCipherDecode(): void
$this->assertEquals($plaintext, $cipher->decode($ciphertext));
}

/**
* Uuid: 70a16473-7339-43df-902d-93408c69e9d1.
*/
#[TestDox('Substitution cipher -> Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method')]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, it's better to skip the example here:

Suggested change
#[TestDox('Substitution cipher -> Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method')]
#[TestDox('Substitution cipher -> Is reversible')]

public function testCipherReversible(): void
{
$cipher = new SimpleCipher('abcdefghij');
$plaintext = 'abcdefghij';
$this->assertEquals($plaintext, $cipher->decode($cipher->encode($plaintext)));
}

/**
* Uuid: 69a1458b-92a6-433a-a02d-7beac3ea91f9.
*/
#[TestDox('Substitution cipher -> Can double shift encode')]
public function testDoubleShiftEncode(): void
{
$cipher = new SimpleCipher('iamapandabear');
Expand All @@ -120,6 +106,10 @@ public function testDoubleShiftEncode(): void
$this->assertEquals($ciphertext, $cipher->encode($plaintext));
}

/**
* Uuid: 21d207c1-98de-40aa-994f-86197ae230fb.
*/
#[TestDox('Substitution cipher -> Can wrap on encode')]
public function testCipherEncodeWrap(): void
{
$cipher = new SimpleCipher('abcdefghij');
Expand All @@ -128,26 +118,39 @@ public function testCipherEncodeWrap(): void
$this->assertEquals($ciphertext, $cipher->encode($plaintext));
}

public function testShiftCipherEncode(): void
/**
* Uuid: a3d7a4d7-24a9-4de6-bdc4-a6614ced0cb3.
*/
#[TestDox('Substitution cipher -> Can wrap on decode')]
public function testCipherDecodeWrap(): void
{
$cipher = new SimpleCipher('dddddddddd');
$plaintext = 'aaaaaaaaaa';
$ciphertext = 'dddddddddd';
$this->assertEquals($ciphertext, $cipher->encode($plaintext));
$cipher = new SimpleCipher('abcdefghij');
$plaintext = 'zzzzzzzzzz';
$ciphertext = 'zabcdefghi';
$this->assertEquals($plaintext, $cipher->decode($ciphertext));
}

public function testShiftCipherDecode(): void
/**
* Uuid: e31c9b8c-8eb6-45c9-a4b5-8344a36b9641.
*/
#[TestDox('Substitution cipher -> Can encode messages longer than the key')]
public function testCanEncodeMessageLongerThanKey(): void
{
$cipher = new SimpleCipher('dddddddddd');
$plaintext = 'aaaaaaaaaa';
$ciphertext = 'dddddddddd';
$this->assertEquals($plaintext, $cipher->decode($ciphertext));
$cipher = new SimpleCipher('abc');
$cipherText = 'iboaqcnecbfcr';
$plainText = 'iamapandabear';
$this->assertEquals($cipherText, $cipher->encode($plainText));
}

public function testShiftCipherReversible(): void
/**
* Uuid: 93cfaae0-17da-4627-9a04-d6d1e1be52e3.
*/
#[TestDox('Substitution cipher -> Can decode messages longer than the key')]
public function testCanDecodeMessageLongerThanKey(): void
{
$cipher = new SimpleCipher('dddddddddd');
$plaintext = 'abcdefghij';
$this->assertEquals($plaintext, $cipher->decode($cipher->encode($plaintext)));
$cipher = new SimpleCipher('abc');
$cipherText = 'iboaqcnecbfcr';
$plainText = 'iamapandabear';
$this->assertEquals($plainText, $cipher->decode($cipherText));
}
}
Loading