xypwn / scadqr

Effortlessly generate QR codes directly in OpenSCAD! No extra dependencies!
MIT License
92 stars 9 forks source link

test: add unit tests for qr code generation #2

Closed yannickbattail closed 1 year ago

yannickbattail commented 1 year ago

a added unitest that generate a .png using the customizer parameter files tests.json then read the qrcode with zbarimg and check the result matches the sources

yannickbattail commented 1 year ago

note: mask_pattern=4 and mask_pattern=7 doesn't seam to work (I commented them)

xypwn commented 1 year ago

Hi, first of all, thanks for your work! I like the idea of adding tests.

Regarding the mask patterns, I already fixed those in commit 3ff1f30dbe12259897478d2750264f6880e22107.

I'm kind of reluctant though to accept a shell script, since the existing code is Python and I don't think it would be very difficult to write a Python script that does the same thing. If you don't know Python I could also write it no problem.

Regarding the actual commands used in testing, I don't quite understand why xvfb-run is necessary since, for me at least, OpenSCAD doesn't open a graphical window when running CLI commands.

Also, I think creating files is unnecessary since we can directly pipe the output into zbarimg. Example: input: openscad -q --autocenter --viewall --camera=0,0,0,0,0,0,200 --export-format png -o - demo.scad | zbarimg -q -- output: QR-Code:some text or url

Additionally, I think adding some tests for larger QR codes would also be a good idea (making sure to use the appropriate library version each time, of course).

yannickbattail commented 1 year ago

You fix the bug with mask patterns 4 and 7, Great job!

I rewrite the tests in python

I pipe the 2 commands openscad and zbarimg to avoid creating the image file

I thing you can write a better python code, i'm a beginner in the language

xypwn commented 1 year ago

Hi, nice work first of all! Although I use Linux myself, I try to keep things as cross-platform as possible, which is also why I decided for Python instead of sh. I'm also a relative beginner, so no worries. I did however modify your code a bit with the following changes made:

Let me know if there's anything wrong with my code, or if I mistakenly changed something important!

Otherwise, when you update your run_tests.py, I'll merge.

#!/usr/bin/python

import argparse
import subprocess

class col:
    RESET = '\033[m'
    RED = '\033[31m'
    GREEN = '\033[32m'
    BRED = '\033[1;31m'
    BGREEN = '\033[1;32m'

tests = [
    ['all', 'https://openscad.org/cheatsheet/'],
    ['wifi_WPA', 'WIFI:T:WPA;S:wifi_network;P:1234;;'],
    ['wifi2_WPA', 'WIFI:T:WPA;S:wireless_fidelity;P:PigOtter;;'],
    ['wifi_WEP', 'WIFI:T:WEP;S:wifi_network;P:1234;;'],
    ['wifi_nopass', 'WIFI:T:nopass;S:wifi_network;P:;;'],
    ['wifi_hidden', 'WIFI:T:WPA;S:wifi_network;P:1234;H:true;'],
    ['phone', 'TEL:+33 1 23 45 67 89'],
    ['text_utf8', 'lorem ipsum'],
    ['text_Shift_JIS', '|orem ipsum'],
    ['error_correction_M', 'lorem ipsum1'],
    ['error_correction_Q', 'lorem ipsum2'],
    ['error_correction_H', 'lorem ipsum3'],
    ['mask_pattern_1', 'lorem ipsum_1'],
    ['mask_pattern_2', 'lorem ipsum_2'],
    ['mask_pattern_3', 'lorem ipsum_3'],
    ['mask_pattern_4', 'lorem ipsum_4'],
    ['mask_pattern_5', 'lorem ipsum_5'],
    ['mask_pattern_6', 'lorem ipsum_6'],
    ['mask_pattern_7', 'lorem ipsum_7'],
]

argparser = argparse.ArgumentParser(prog='test.py',description='Run ScadQR tests')
argparser.add_argument('-s', '--openscad', default='openscad', help='OpenSCAD executable')
argparser.add_argument('-z', '--zbarimg', default='zbarimg', help='zbarimg QR code reader executable')
args = argparser.parse_args()

def exe_not_found(name, path, flag):
    print(f'{name} executable at "{path}" not found.')
    print(f'Please install {name} or use the "{flag}" flag to specify a custom executable.')

print('Running tests...')

tests_passed = 0
for i, test in enumerate(tests):
    testname = test[0]
    expect = 'QR-Code:'+test[1]

    print(f' {i}/{len(tests)}', end='\r')

    img = ''
    try:
        img = subprocess.check_output([
            args.openscad,
            '-q',
            '--autocenter',
            '--viewall',
            '--camera=0,0,0,0,0,0,200',
            '-p', 'tests.json',
            '-P', testname,
            '--export-format', 'png',
            '-o', '-',
            'demo.scad',
        ])
    except FileNotFoundError:
        exe_not_found('OpenSCAD', args.openscad, '-s')
        exit()

    res = ''
    try:
        res = subprocess.check_output([
            args.zbarimg,
            '-q',
            '-',
        ], input=img).decode('utf-8').removesuffix('\n')
    except FileNotFoundError:
        exe_not_found('zbarimg', args.zbarimg, '-z')
        exit()

    if (res == expect):
        tests_passed += 1
    else:
        print(f'{col.RED}failed{col.RESET} test "{testname}": got "{res}", expected "{expect}"')

if tests_passed == len(tests):
    print(f'{col.BGREEN}PASS{col.RESET} {tests_passed}/{len(tests)} tests passed')
else:
    print(f'{col.BRED}FAIL{col.RESET} {tests_passed}/{len(tests)} tests passed')
yannickbattail commented 1 year ago

Great job!

I would just add exit(1) when one or more test failed

xypwn commented 1 year ago

Great idea and thanks for your contribution!