Skip to content

Commit

Permalink
Port cpp version to C with cmocka.
Browse files Browse the repository at this point in the history
  • Loading branch information
codecop committed Jan 22, 2025
1 parent 8b52546 commit f3940e2
Show file tree
Hide file tree
Showing 6 changed files with 344 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/c.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Test C

on:
push:
paths:
- 'c/**'
- '.github/workflows/c.yml'
pull_request:
paths:
- 'c/**'
- '.github/workflows/c.yml'

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v3

- name: Set up dependencies
run: |
sudo apt-get update
sudo apt-get install libcmocka-dev
- name: Build
working-directory: c
run: gcc -std=c99 Ocr.c OcrTest.c -l cmocka -o OcrTest

- name: Test
working-directory: c
run: ./OcrTest
50 changes: 50 additions & 0 deletions c/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Language: Cpp
AccessModifierOffset: -4
AlignEscapedNewlinesLeft: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackParameters: false
BreakBeforeBinaryOperators: false
BreakBeforeBraces: Stroustrup
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 90
CommentPragmas: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: false
NamespaceIndentation: None
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpacesInParentheses: false
Cpp11BracedListStyle: true
Standard: Cpp11
TabWidth: 4
UseTab: Never
58 changes: 58 additions & 0 deletions c/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.idea
cmake-build-debug

# Prerequisites
*.d

# Object files
*.o
*.ko
*.obj
*.elf

# Linker output
*.ilk
*.map
*.exp

# Precompiled Headers
*.gch
*.pch

# Libraries
*.lib
*.a
*.la
*.lo

# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib

# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex

# Debug files
*.dSYM/
*.su
*.idb
*.pdb

# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

# local help scripts
_test.bat
78 changes: 78 additions & 0 deletions c/Ocr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <stdbool.h>
#include <string.h>

#include "Ocr.h"

const char NUMERALS[10][4][4 + 1] = {{" _ ", /* */
"| | ", /* */
"|_| ", /* */
" "}, /* */
{" ", /* */
" | ", /* */
" | ", /* */
" "}, /* */
{" _ ", /* */
" _| ", /* */
"|_ ", /* */
" "}, /* */
{" _ ", /* */
" _| ", /* */
" _| ", /* */
" "}, /* */
{" ", /* */
"|_| ", /* */
" | ", /* */
" "}, /* */
{" _ ", /* */
"|_ ", /* */
" _| ", /* */
" "}, /* */
{" _ ", /* */
"|_ ", /* */
"|_| ", /* */
" "}, /* */
{" _ ", /* */
" | ", /* */
" | ", /* */
" "}, /* */
{" _ ", /* */
"|_| ", /* */
"|_| ", /* */
" "}, /* */
{" _ ", /* */
"|_| ", /* */
" _| ", /* */
" "}};

void parse(char lines[][36 + 1], size_t numberLines, char result[][13 + 1], size_t* resultLines)
{
*resultLines = 0;
for (size_t i = 0; i < numberLines; i += 4) {
char work[13 + 1] = " ";
for (size_t pos = 0; pos < 9; ++pos) {
work[pos] = '?';
bool got1 = false;
for (size_t numeral = 0; numeral <= 9; ++numeral) {
bool ok = true;
for (size_t row = 0; row < 4; ++row) {
for (size_t col = 0; col < 4; ++col) {
if (NUMERALS[numeral][row][col] != lines[i + row][4 * pos + col]) {
ok = false;
}
}
}
if (ok) {
work[pos] = (char)(numeral + (int)'0');
got1 = true;
break;
}
}
if (!got1) {
work[10] = 'I';
work[11] = work[12] = 'L';
}
}

strcpy(result[(*resultLines)++], work);
}
}
6 changes: 6 additions & 0 deletions c/Ocr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef OCR_OCR_H
#define OCR_OCR_H

void parse(char lines[][36 + 1], size_t numberLines, char result[][13 + 1], size_t* resultLines);

#endif // OCR_OCR_H
121 changes: 121 additions & 0 deletions c/OcrTest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include <setjmp.h> /* jmp_buf for mocka */
#include <stdarg.h> /* va_start for mocka */
#include <stddef.h> /* size_t for mocka */

#include <cmocka.h>

#include "Ocr.h"

static void test_parses_one_record_with_888888888(void** state)
{
(void)state; /* unused */
char lines[][36 + 1] = {" _ _ _ _ _ _ _ _ _ ", /* */
"|_| |_| |_| |_| |_| |_| |_| |_| |_| ", /* */
"|_| |_| |_| |_| |_| |_| |_| |_| |_| ", /* */
" "};
char result[][13 + 1] = {""};
size_t resultLines = 0;

parse(lines, 4, result, &resultLines);

assert_string_equal("888888888 ", result[0]);
}

static void test_parses_two_records_with_888888888(void** state)
{
(void)state; /* unused */
char lines[][36 + 1] = {" _ _ _ _ _ _ _ _ _ ", /* */
"|_| |_| |_| |_| |_| |_| |_| |_| |_| ", /* */
"|_| |_| |_| |_| |_| |_| |_| |_| |_| ", /* */
" ", /* */
" _ _ _ _ _ _ _ _ _ ", /* */
"|_| |_| |_| |_| |_| |_| |_| |_| |_| ", /* */
"|_| |_| |_| |_| |_| |_| |_| |_| |_| ", /* */
" "};
char result[][13 + 1] = {"", ""};
size_t resultLines = 0;

parse(lines, 8, result, &resultLines);

assert_string_equal("888888888 ", result[0]);
assert_string_equal("888888888 ", result[1]);
}

static void test_parses_one_record_with_123456790(void** state)
{
(void)state; /* unused */
char lines[][36 + 1] = {" _ _ _ _ _ _ _ ", /* */
" | _| _| |_| |_ |_ | |_| | | ", /* */
" | |_ _| | _| |_| | _| |_| ", /* */
" "};
char result[1][13 + 1] = {""};
size_t resultLines = 0;

parse(lines, 4, result, &resultLines);

assert_string_equal("123456790 ", result[0]);
}

static void test_parses_two_records(void** state)
{
(void)state; /* unused */
char lines[][36 + 1] = {" _ _ _ _ _ _ _ ", /* */
" | _| _| |_| |_ |_ | |_| | | ", /* */
" | |_ _| | _| |_| | _| |_| ", /* */
" ", /* */
" _ _ _ _ _ _ _ ", /* */
"|_| |_| | |_| | |_| _| _| _| ", /* */
" _| | | |_| | | |_ |_ |_ ", /* */
" "};
char result[2][13 + 1] = {"", ""};
size_t resultLines = 0;

parse(lines, 8, result, &resultLines);

assert_string_equal("123456790 ", result[0]);
assert_string_equal("947874222 ", result[1]);
}

static void test_parses_illegal_digit(void** state)
{
(void)state; /* unused */
char lines[][36 + 1] = {" _ _ _ _ _ _ _ ", /* */
" | _| |_| _| |_ |_ | |_| | | ", /* */
" | |_ _ | _| |_| | _| |_| ", /* */
" "};
char result[1][13 + 1] = {""};
size_t resultLines = 0;

parse(lines, 4, result, &resultLines);

assert_string_equal("12??56790 ILL", result[0]);
}

static void test_checksum_fail_returns_ERR(void** state)
{
(void)state; /* unused */
char lines[][36 + 1] = {" _ _ _ _ _ _ ", /* */
"|_ |_ |_| _| | | |_| |_| |_ ", /* */
"|_| |_| | _| | | | _| _| ", /* */
" "};
char result[1][13 + 1] = {""};
size_t resultLines = 0;

parse(lines, 4, result, &resultLines);

assert_string_equal("664371495 ERR", result[0]);
}

int main(void)
{
const struct CMUnitTest test_suite[] = {
cmocka_unit_test(test_parses_one_record_with_888888888), /* */
cmocka_unit_test(test_parses_two_records_with_888888888), /* */
cmocka_unit_test(test_parses_one_record_with_123456790), /* */
cmocka_unit_test(test_parses_two_records), /* */
cmocka_unit_test(test_parses_illegal_digit), /* */
// cmocka_unit_test(test_checksum_fail_returns_ERR), /* */
};

return cmocka_run_group_tests(test_suite, NULL, NULL);
}

0 comments on commit f3940e2

Please sign in to comment.