1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-07 16:23:38 +03:00

Device tests updates (#9246)

Stop pyexpect from closing serial port when running with WSL2
Remove makefile flags & opts making it too silent. At some point it makes a lot of useful info just disappear. There are external means of silencing make, so probably best to leave useful data always available

Replace SPIFFS with LittleFS in FS test
Re-use certs-from-mozilla.py in FS test

Fix libc tests w/o -fno-builtin not actually testing anything, also add the flag via .globals.h in case it breaks
Fix libc tests generating warnings when using invalid (but safe) size arguments
This commit is contained in:
Max Prokhorov 2025-05-21 16:21:08 +03:00 committed by GitHub
parent a5f18b5f91
commit 92002ece2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 408 additions and 322 deletions

View File

@ -13,15 +13,9 @@ import os
import sys import sys
from shutil import which from shutil import which
from subprocess import Popen, PIPE, call from io import StringIO
try: from subprocess import Popen, PIPE, call, CalledProcessError
from urllib.request import urlopen from urllib.request import urlopen
except Exception:
from urllib2 import urlopen
try:
from StringIO import StringIO
except Exception:
from io import StringIO
# check if ar and openssl are available # check if ar and openssl are available
if which('ar') is None and not os.path.isfile('./ar') and not os.path.isfile('./ar.exe'): if which('ar') is None and not os.path.isfile('./ar') and not os.path.isfile('./ar.exe'):
@ -62,10 +56,10 @@ for i in range(0, len(pems)):
thisPem = pems[i].replace("'", "") thisPem = pems[i].replace("'", "")
print(names[i] + " -> " + certName) print(names[i] + " -> " + certName)
ssl = Popen(['openssl','x509','-inform','PEM','-outform','DER','-out', certName], shell = False, stdin = PIPE) ssl = Popen(['openssl','x509','-inform','PEM','-outform','DER','-out', certName], shell = False, stdin = PIPE)
pipe = ssl.stdin ssl.communicate(thisPem.encode('utf-8'))
pipe.write(thisPem.encode('utf-8')) ret = ssl.wait()
pipe.close() if ret != 0:
ssl.wait() raise CalledProcessError(ret, certName)
if os.path.exists(certName): if os.path.exists(certName):
derFiles.append(certName) derFiles.append(certName)
idx = idx + 1 idx = idx + 1

View File

@ -1,45 +1,65 @@
SHELL := /bin/bash SHELL := /bin/bash
V ?= 0
ESP8266_CORE_PATH ?= $(realpath ../..) ESP8266_CORE_PATH ?= $(shell git rev-parse --show-toplevel)
BUILD_DIR ?= $(PWD)/.build
HARDWARE_DIR ?= $(PWD)/.hardware BUILD_DIR ?= $(PWD)/build
BS_DIR ?= $(PWD)/libraries/BSTest
PYTHON ?= python3 PYTHON ?= python3
ESPTOOL ?= $(PYTHON) $(ESP8266_CORE_PATH)/tools/esptool/esptool.py ESPTOOL ?= $(PYTHON) $(ESP8266_CORE_PATH)/tools/esptool/esptool.py
MKSPIFFS ?= $(ESP8266_CORE_PATH)/tools/mkspiffs/mkspiffs
VENV_PYTHON ?= $(BS_DIR)/virtualenv/bin/python
VENV_JUNIT2HTML ?= $(BS_DIR)/virtualenv/bin/junit2html
MKFS ?= $(ESP8266_CORE_PATH)/tools/mklittlefs/mklittlefs
UPLOAD_PORT ?= $(shell ls /dev/tty* | grep -m 1 -i USB) UPLOAD_PORT ?= $(shell ls /dev/tty* | grep -m 1 -i USB)
UPLOAD_BAUD ?= 460800 UPLOAD_BAUD ?= 460800
UPLOAD_BOARD ?= nodemcu
BS_DIR ?= libraries/BSTest TEST_BAUD ?= 115200
DEBUG_LEVEL ?= lvl=None____ BUILD_TOOL ?= arduino-cli
FQBN ?= esp8266com:esp8266:generic:xtal=160,FlashFreq=40,FlashMode=dio,baud=115200,eesz=4M1M,ip=lm2f,ResetMethod=nodemcu,dbg=Serial,$(DEBUG_LEVEL)
BUILD_TOOL := $(ARDUINO_IDE_PATH)/arduino-builder BUILD_BOARD ?= generic
BUILD_CPU ?= 160
BUILD_SIZE ?= 4M1M
BUILD_LWIP ?= lm2f
BUILD_EXTRA ?= ,dbg=Serial,lvl=CORE
FQBN ?= esp8266com:esp8266:$(BUILD_BOARD):xtal=$(BUILD_CPU),baud=$(TEST_BAUD),eesz=$(BUILD_SIZE),ip=$(BUILD_LWIP)$(BUILD_EXTRA)
TEST_CONFIG := test_env.cfg TEST_CONFIG := test_env.cfg
TEST_RESULT_XML := test_result.xml
TEST_REPORT_XML := test_report.xml TEST_REPORT_XML := test_report.xml
TEST_REPORT_HTML := test_report.html TEST_REPORT_HTML := test_report.html
ifeq ("$(MOCK)", "1")
# To enable a test for mock testing, just rename dir+files to '*_sw_*'
TEST_LIST ?= $(wildcard test_sw_*/*.ino)
else
TEST_LIST ?= $(wildcard test_*/*.ino) TEST_LIST ?= $(wildcard test_*/*.ino)
BUILD_FLAGS ?=
BS_FLAGS ?=
# To enable a test for mock testing, just rename dir+files to '*_sw_*'
ifeq ("$(MOCK)", "1")
TEST_LIST := $(filter test_sw_%.ino,$(TEST_LIST))
NO_UPLOAD := 1
NO_RUN := 1
endif endif
ifneq ("$(V)","1") # To enable verbose mode, call `make V=1` ...
SILENT = @ V ?= 0
REDIR = >& /dev/null ifeq ("$(V)", "1")
else BUILD_FLAGS += --verbose
BUILDER_DEBUG_FLAG = -verbose BS_FLAGS += --debug
RUNNER_DEBUG_FLAG = -d
#UPLOAD_VERBOSE_FLAG = -v
endif endif
# ${sketch}.py helper script when building locally
mock_script = \
`test -f $(addsuffix .py, $(basename $(1))) && echo "--mock $(addsuffix .py, $(basename $(1)))" || echo ""`
help: help:
@echo @echo
@echo 'make list - show list of tests' @echo 'make list - show list of tests'
@echo 'make sometest/sometest.ino - run one test' @echo 'make sometest/sometest.ino - run one test'
@echo 'make all - run all tests' @echo 'make all - run all tests'
@echo 'make MOCK=1 all - run all emulation-on-host compatible tests' @echo 'make MOCK=1 all - run all emulation-on-host compatible tests'
@echo 'variables needed: $$ARDUINO_IDE_PATH $$ESP8266_CORE_PATH'
@echo 'make options: V=1 NO_BUILD=1 NO_UPLOAD=1 NO_RUN=1 MOCK=1' @echo 'make options: V=1 NO_BUILD=1 NO_UPLOAD=1 NO_RUN=1 MOCK=1'
@echo @echo
@ -49,110 +69,132 @@ all: count tests test_report
$(TEST_LIST): | virtualenv $(TEST_CONFIG) $(BUILD_DIR) $(HARDWARE_DIR) $(TEST_LIST): | virtualenv $(TEST_CONFIG) $(BUILD_DIR) $(HARDWARE_DIR)
.NOTPARALLEL: $(TEST_LIST)
tests: showtestlist $(TEST_LIST) tests: showtestlist $(TEST_LIST)
showtestlist: showtestlist:
@echo "-------------------------------- test list:" @echo "-------------------------------- test list:"
@echo $(TEST_LIST) @printf '%s\n' $(TEST_LIST)
@echo "--------------------------------" @echo "--------------------------------"
$(TEST_LIST): LOCAL_BUILD_DIR=$(BUILD_DIR)/$(notdir $@) $(TEST_LIST): LOCAL_BUILD_DIR=$(BUILD_DIR)/$(notdir $@)
$(TEST_LIST): LOCAL_DATA_IMG=data.img
$(TEST_LIST): define build-arduino
@echo "--------------------------------" rm -f $(LOCAL_BUILD_DIR)/build.options.json
@echo "Running test '$@' of $(words $(TEST_LIST)) tests" $(BUILD_TOOL) compile \
$(SILENT)mkdir -p $(LOCAL_BUILD_DIR) $(BUILD_FLAGS) \
ifeq ("$(MOCK)", "1") --libraries "$(PWD)/libraries" \
@echo Compiling $(notdir $@) --warnings=all \
(cd ../host; make D=$(V) ULIBDIRS=../device/libraries/BSTest ../device/$(@:%.ino=%)) --build-path $(LOCAL_BUILD_DIR) \
$(SILENT)$(BS_DIR)/virtualenv/bin/python \ --fqbn=$(FQBN) \
$(BS_DIR)/runner.py \
$(RUNNER_DEBUG_FLAG) \
-e "$(ESP8266_CORE_PATH)/tests/host/bin/$(@:%.ino=%)" \
-n $(basename $(notdir $@)) \
-o $(LOCAL_BUILD_DIR)/test_result.xml \
--env-file $(TEST_CONFIG) \
`test -f $(addsuffix .py, $(basename $@)) && echo "-m $(addsuffix .py, $(basename $@))" || echo ""`
else
ifneq ("$(NO_BUILD)","1")
@test -n "$(ARDUINO_IDE_PATH)" || (echo "Please export ARDUINO_IDE_PATH" && exit 1)
@echo Compiling $(notdir $@)
@rm -f $(LOCAL_BUILD_DIR)/build.options.json
$(SILENT)$(BUILD_TOOL) -compile -logger=human \
-libraries "$(PWD)/libraries" \
-core-api-version="10608" \
-warnings=all \
$(BUILDER_DEBUG_FLAG) \
-build-path $(LOCAL_BUILD_DIR) \
-tools $(ARDUINO_IDE_PATH)/tools-builder \
-hardware $(HARDWARE_DIR)\
-hardware $(ARDUINO_IDE_PATH)/hardware \
-fqbn=$(FQBN) \
$@ $@
endif endef
ifneq ("$(NO_UPLOAD)","1")
@test -n "$(UPLOAD_PORT)" || (echo "Failed to detect upload port, please export UPLOAD_PORT manually" && exit 1) define build-mock
@test -e $(dir $@)/make_spiffs.py && ( \ (cd $(ESP8266_CORE_PATH)/test/host; \
echo "Generating and uploading SPIFFS" && \ $(MAKE) D=$(V) ULIBDIRS=$(PWD)/libraries/BSTest $(PWD)/$(@:%.ino=%))
(cd $(dir $@) && $(PYTHON) ./make_spiffs.py $(REDIR) ) && \ $(VENV_PYTHON) $(BS_DIR)/runner.py \
$(MKSPIFFS) --create $(dir $@)data/ --size 0xFB000 \ $(BS_FLAGS) \
--block 8192 --page 256 $(LOCAL_BUILD_DIR)/spiffs.img $(REDIR) && \ --name $(basename $(notdir $@)) \
$(ESPTOOL) $(UPLOAD_VERBOSE_FLAG) \ --output $(LOCAL_BUILD_DIR)/$(TEST_RESULT_XML) \
--env-file $(TEST_CONFIG) \
$(call mock_script,$@) \
executable "$(ESP8266_CORE_PATH)/tests/host/bin/$(@:%.ino=%)" || echo ""`
endef
define upload-data
@test -n "$(UPLOAD_PORT)" \
|| (echo "Failed to detect upload port, please export UPLOAD_PORT manually" && exit 1)
@test ! \( -d $(dir $@)/data/ \) -a \( -e $(dir $@)/make_data.py \) && \
(cd $(dir $@) && ./make_data.py ) || echo "Filesystem creation skipped"
@test -d $(dir $@)/data/ && ( \
$(MKFS) \
--create $(dir $@)/data/ \
--size 0xFB000 \
--block 8192 \
--page 256 \
$(LOCAL_BUILD_DIR)/$(LOCAL_DATA_IMG) && \
$(ESPTOOL) \
--chip esp8266 \ --chip esp8266 \
--port $(UPLOAD_PORT) \ --port $(UPLOAD_PORT) \
--baud $(UPLOAD_BAUD) \ --baud $(UPLOAD_BAUD) \
--after no_reset \ --after no_reset \
write_flash 0x300000 $(LOCAL_BUILD_DIR)/spiffs.img $(REDIR) ) \ write_flash 0x300000 $(LOCAL_BUILD_DIR)/$(LOCAL_DATA_IMG) ) \
|| (echo "No SPIFFS to upload") && (echo "Uploaded filesystem") \
@echo Uploading binary || (echo "Filesystem upload skipped")
$(SILENT)$(ESPTOOL) $(UPLOAD_VERBOSE_FLAG) \ endef
define upload-binary
@test -n "$(UPLOAD_PORT)" \
|| (echo "Failed to detect upload port, please export UPLOAD_PORT manually" && exit 1)
$(ESPTOOL) \
--chip esp8266 \ --chip esp8266 \
--port $(UPLOAD_PORT) \ --port $(UPLOAD_PORT) \
--baud $(UPLOAD_BAUD) \ --baud $(UPLOAD_BAUD) \
--after no_reset \ --after no_reset \
write_flash 0x0 $(LOCAL_BUILD_DIR)/$(notdir $@).bin $(REDIR) # no reset write_flash 0x0 $(LOCAL_BUILD_DIR)/$(notdir $@).bin
endif endef
ifneq ("$(NO_RUN)","1")
@test -n "$(UPLOAD_PORT)" || (echo "Failed to detect upload port, please export UPLOAD_PORT manually" && exit 1) define run-test
@test -n "$(UPLOAD_PORT)" \
|| (echo "Failed to detect upload port, please export UPLOAD_PORT manually" && exit 1)
@echo Running tests @echo Running tests
$(SILENT)$(ESPTOOL) $(UPLOAD_VERBOSE_FLAG) \ $(ESPTOOL) \
--chip esp8266 \ --chip esp8266 \
--port $(UPLOAD_PORT) \ --port $(UPLOAD_PORT) \
--baud $(UPLOAD_BAUD) \ --baud $(UPLOAD_BAUD) \
read_flash_status $(REDIR) # reset read_flash_status # reset via implicit stub reboot
$(SILENT)$(BS_DIR)/virtualenv/bin/python \ $(VENV_PYTHON) $(BS_DIR)/runner.py \
$(BS_DIR)/runner.py \ $(BS_FLAGS) \
$(RUNNER_DEBUG_FLAG) \ --name $(basename $(notdir $@)) \
-p $(UPLOAD_PORT) \ --output $(LOCAL_BUILD_DIR)/$(TEST_RESULT_XML) \
-n $(basename $(notdir $@)) \ --env-file $(TEST_CONFIG) \
-o $(LOCAL_BUILD_DIR)/test_result.xml \ $(call mock_script,$@) \
--env-file $(TEST_CONFIG) \ port $(UPLOAD_PORT) \
`test -f $(addsuffix .py, $(basename $@)) && echo "-m $(addsuffix .py, $(basename $@))" || echo ""` --baudrate $(TEST_BAUD)
endef
$(TEST_LIST):
@echo "--------------------------------"
@echo "Running test '$@' of $(words $(TEST_LIST)) tests"
mkdir -p $(LOCAL_BUILD_DIR)
ifneq ("$(NO_BUILD)","1")
@echo Building $(notdir $@)
ifeq ("$(MOCK)", "1")
$(build-mock)
else
$(build-arduino)
endif endif
endif endif
ifneq ("$(NO_UPLOAD)","1")
$(upload-filesystem)
$(upload-binary)
endif
ifneq ("$(NO_RUN)","1")
$(run-test)
endif
$(TEST_REPORT_XML): $(HARDWARE_DIR) virtualenv $(TEST_REPORT_XML): virtualenv
$(SILENT)$(BS_DIR)/xunitmerge $(shell find $(BUILD_DIR) -name 'test_result.xml' | xargs echo) $(TEST_REPORT_XML) $(BS_DIR)/xunitmerge \
$(shell find $(BUILD_DIR) -name '$(TEST_RESULT_XML)' | xargs echo) \
$(TEST_REPORT_XML)
$(TEST_REPORT_HTML): $(TEST_REPORT_XML) | virtualenv $(TEST_REPORT_HTML): $(TEST_REPORT_XML) | virtualenv
$(SILENT)$(BS_DIR)/virtualenv/bin/junit2html $< $@ $(VENV_JUNIT2HTML) $< $@
test_report: $(TEST_REPORT_HTML) test_report: $(TEST_REPORT_HTML)
@echo "Test report generated in $(TEST_REPORT_HTML)" @echo "Test report generated in $(TEST_REPORT_HTML)"
$(BUILD_DIR): $(BUILD_DIR):
mkdir -p $(BUILD_DIR) @mkdir -p $(BUILD_DIR)
$(HARDWARE_DIR):
mkdir -p $(HARDWARE_DIR)/esp8266com
cd $(HARDWARE_DIR)/esp8266com && ln -s $(realpath $(ESP8266_CORE_PATH)) esp8266
virtualenv: virtualenv:
@make -C $(BS_DIR) PYTHON=$(PYTHON) virtualenv @make -C $(BS_DIR) PYTHON=$(PYTHON) virtualenv
clean: clean:
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)
rm -rf $(HARDWARE_DIR)
rm -rf $(BS_DIR)/virtualenv rm -rf $(BS_DIR)/virtualenv
rm -f $(TEST_REPORT_HTML) $(TEST_REPORT_XML) rm -f $(TEST_REPORT_HTML) $(TEST_REPORT_XML)

View File

@ -1,40 +1,32 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from __future__ import print_function
import serial
import pexpect import pexpect
from pexpect import EOF, TIMEOUT, fdpexpect from pexpect import EOF, TIMEOUT, fdpexpect
import sys
import os
import time
import argparse
import serial
import subprocess
from importlib.machinery import SourceFileLoader
try:
from configparser import ConfigParser
except:
from ConfigParser import ConfigParser
import itertools
try:
from urllib.parse import urlparse, urlencode
except ImportError:
from urlparse import urlparse
from junit_xml import TestSuite, TestCase from junit_xml import TestSuite, TestCase
try:
from cStringIO import StringIO import argparse
except: import itertools
try: import os
from StringIO import StringIO import subprocess
except ImportError: import sys
from io import StringIO import time
from configparser import ConfigParser
from importlib.machinery import SourceFileLoader
from io import StringIO
from urllib.parse import urlparse, urlencode
import mock_decorators import mock_decorators
debug = False debug = False
#debug = True
sys.path.append(os.path.abspath(__file__)) sys.path.append(os.path.abspath(__file__))
IS_WSL = len(os.environ.get("WSL_DISTRO_NAME", "")) > 0
def debug_print(*args, **kwargs): def debug_print(*args, **kwargs):
if not debug: if not debug:
return return
@ -235,9 +227,11 @@ class BSTestRunner(object):
ser = None ser = None
def spawn_port(port_name, baudrate=115200): def spawn_port(port_name, baudrate=115200, close=True):
global ser global ser
ser = serial.serial_for_url(port_name, baudrate=baudrate) ser = serial.serial_for_url(port_name, baudrate=baudrate)
if not close:
ser.close = lambda: None
return fdpexpect.fdspawn(ser, 'wb', timeout=0, encoding='cp437') return fdpexpect.fdspawn(ser, 'wb', timeout=0, encoding='cp437')
def spawn_exec(name): def spawn_exec(name):
@ -250,30 +244,39 @@ def run_tests(spawn, name, mocks, env_vars):
def parse_args(): def parse_args():
parser = argparse.ArgumentParser(description='BS test runner') parser = argparse.ArgumentParser(description='BS test runner')
parser.add_argument('-d', '--debug', help='Send test output to stderr', action='store_true') parser.add_argument('--debug', help='Send test output to stderr', action='store_true')
parser.add_argument('-p', '--port', help='Talk to the test over serial') parser.add_argument('--name', help='Test run name')
parser.add_argument('-e', '--executable', help='Talk to the test executable') parser.add_argument('--output', help='Output JUnit format test report')
parser.add_argument('-n', '--name', help='Test run name') parser.add_argument('--mock', help='Set python script to use for mocking purposes')
parser.add_argument('-o', '--output', help='Output JUnit format test report')
parser.add_argument('-m', '--mock', help='Set python script to use for mocking purposes')
parser.add_argument('--env-file', help='File containing a list of environment variables to set', type=argparse.FileType('r')) parser.add_argument('--env-file', help='File containing a list of environment variables to set', type=argparse.FileType('r'))
sub = parser.add_subparsers()
def as_spawn_port(args):
return spawn_port(args.port, args.baudrate, args.close)
port = sub.add_parser('port')
port.add_argument('port', type=str)
port.add_argument('--baudrate', help='Serial port baudrate', type=int, default=115200)
port.add_argument('--close', help='Close serial port after the test', action=argparse.BooleanOptionalAction, default=not IS_WSL)
port.set_defaults(func=as_spawn_port)
def as_spawn_exec(args):
return spawn_exec(args.executable)
exe = sub.add_parser('executable')
exe.add_argument('executable', help='Talk to the test executable')
exe.set_defaults(func=as_spawn_exec)
return parser.parse_args() return parser.parse_args()
def main(): def main():
args = parse_args() args = parse_args()
spawn_func = None
spawn_arg = None
if args.port is not None:
spawn_func = spawn_port
spawn_arg = args.port
elif args.executable is not None:
spawn_func = spawn_exec
spawn_arg = args.executable
name = args.name or "" name = args.name or ""
global debug global debug
if args.debug: debug = args.debug
debug = True if args.func is None:
if spawn_func is None:
debug_print("Please specify port or executable", file=sys.stderr) debug_print("Please specify port or executable", file=sys.stderr)
return 1 return 1
env_vars = [] env_vars = []
@ -287,7 +290,8 @@ def main():
if args.mock is not None: if args.mock is not None:
mocks_mod = SourceFileLoader('mocks', args.mock).load_module() mocks_mod = SourceFileLoader('mocks', args.mock).load_module()
mocks = mock_decorators.env mocks = mock_decorators.env
with spawn_func(spawn_arg) as sp:
with args.func(args) as sp:
ts = run_tests(sp, name, mocks, env_vars) ts = run_tests(sp, name, mocks, env_vars)
if args.output: if args.output:
with open(args.output, "w") as f: with open(args.output, "w") as f:

View File

@ -0,0 +1 @@
../../../libraries/ESP8266WiFi/examples/BearSSL_CertStore/certs-from-mozilla.py

View File

@ -1,71 +0,0 @@
#!/usr/bin/python3
# This script pulls the list of Mozilla trusted certificate authorities
# from the web at the "mozurl" below, parses the file to grab the PEM
# for each cert, and then generates DER files in a new ./data directory
# Upload these to a SPIFFS filesystem and use the CertManager to parse
# and use them for your outgoing SSL connections.
#
# Script by Earle F. Philhower, III. Released to the public domain.
from __future__ import print_function
import csv
import os
import sys
from subprocess import Popen, PIPE, call
try:
from urllib.request import urlopen
except:
from urllib2 import urlopen
try:
from StringIO import StringIO
except:
from io import StringIO
# Mozilla's URL for the CSV file with included PEM certs
mozurl = "https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV"
# Load the manes[] and pems[] array from the URL
names = []
pems = []
response = urlopen(mozurl)
csvData = response.read()
if sys.version_info[0] > 2:
csvData = csvData.decode('utf-8')
csvFile = StringIO(csvData)
csvReader = csv.reader(csvFile)
for row in csvReader:
names.append(row[0]+":"+row[1]+":"+row[2])
pems.append(row[30])
del names[0] # Remove headers
del pems[0] # Remove headers
# Try and make ./data, skip if present
try:
os.mkdir("data")
except:
pass
derFiles = []
idx = 0
# Process the text PEM using openssl into DER files
for i in range(0, len(pems)):
certName = "data/ca_%03d.der" % (idx);
thisPem = pems[i].replace("'", "")
print(names[i] + " -> " + certName)
ssl = Popen(['openssl','x509','-inform','PEM','-outform','DER','-out', certName], shell = False, stdin = PIPE)
pipe = ssl.stdin
pipe.write(thisPem.encode('utf-8'))
pipe.close()
ssl.wait()
if os.path.exists(certName):
derFiles.append(certName)
idx = idx + 1
if os.path.exists("data/certs.ar"):
os.unlink("data/certs.ar");
arCmd = ['ar', 'q', 'data/certs.ar'] + derFiles;
call( arCmd )
for der in derFiles:
os.unlink(der)

View File

@ -1,7 +1,7 @@
// Stress test the BearSSL connection options to determine // Stress test the BearSSL connection options to determine
// maximum memory use for different SSL connections and // maximum memory use for different SSL connections and
// SPIFFS certstore usage. Before running you need to run // filesystem certstore usage. Before running the test you need to
// certs-from-mozilla.py and upload the generated SPIFFS file. // update them with certs-from-mozilla.py and upload the generated file.
// //
// For more info on CertStores, see the BearSSL_CertStore example // For more info on CertStores, see the BearSSL_CertStore example
// //
@ -12,7 +12,7 @@
#include <BSTest.h> #include <BSTest.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <CertStoreBearSSL.h> #include <CertStoreBearSSL.h>
#include <FS.h> #include <LittleFS.h>
#include <time.h> #include <time.h>
#include <StackThunk.h> #include <StackThunk.h>
@ -45,11 +45,11 @@ bool pretest()
delay(500); delay(500);
} }
setClock(); setClock();
SPIFFS.begin(); LittleFS.begin();
int numCerts = certStore.initCertStore(SPIFFS, "/certs.idx", "/certs.ar"); int numCerts = certStore.initCertStore(LittleFS, "/certs.idx", "/certs.ar");
Serial.printf("Number of CA certs read: %d\n", numCerts); Serial.printf("Number of CA certs read: %d\n", numCerts);
if (numCerts == 0) { if (numCerts == 0) {
Serial.printf("No certs found. Did you run certs-from-mozill.py and upload the SPIFFS directory before running?\n"); Serial.printf("No certs found. Did you run upload script?\n");
return false; return false;
} }
return true; return true;

View File

@ -3,51 +3,130 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#define memcmp memcmp_P #include <sys/pgmspace.h>
#define memcpy memcpy_P
#define memmem memmem_P
#define memchr memchr_P
#define strcat strcat_P
#define strncat strncat_P
#define strcpy strcpy_P
#define strncpy strncpy_P
#define strlen strlen_P
#define strnlen strnlen_P
#define strcmp strcmp_P
#define strncmp strncmp_P
_CONST char* it = "<UNSET>"; /* Routine name for message routines. */ /* esp8266/Arduino note
*
* Prevent the compiler from
* - solving test cases below at compile time, effectively removing any checks
* - optimizing out libc func calls, replacing them with bytewise memory access
*
* Plus, test framework cannot pass -fno-builtin-... per-file, only globally
*/
#define xDST_SRC_N(T, NAME)\
static T* __attribute__((used, noinline)) x ## NAME (T* dst, const T* src, size_t n)\
{\
return NAME (dst, src, n);\
}
xDST_SRC_N (void, memcpy)
xDST_SRC_N (void, memmove)
xDST_SRC_N (char, strncat)
xDST_SRC_N (char, strncpy)
#define xDST_SRC(T, NAME)\
static T* __attribute__((used, noinline)) x ## NAME (T* dst, const T* src)\
{\
return NAME (dst, src);\
}
xDST_SRC (char, strcat)
xDST_SRC (char, strcpy)
#define xS1_S2_N(RET, T, NAME)\
static RET __attribute__((used, noinline)) x ## NAME (const T *s1, const T *s2, size_t n)\
{\
return NAME (s1, s2, n);\
}
xS1_S2_N(int, void, memcmp)
xS1_S2_N(int, char, strncmp)
static int __attribute__((used, noinline)) xstrcmp (const char *s1, const char *s2)
{
return strcmp (s1, s2);
}
static void* __attribute__((used, noinline)) xmemchr (const void* s, int c, size_t n)
{
return memchr (s, c, n);
}
static size_t __attribute__((used, noinline)) xstrlen (const char* s)
{
return strlen (s);
}
#if 0
/* TODO remove when libc supports pointers to flash */
#undef PSTR
#define PSTR(X) X
#define memcmp(s1,s2,n) xmemcmp(s1,PSTR(s2),n)
#define memcpy(dest,src,n) xmemcpy(dest,PSTR(src),n)
#define memmove(dest,src,n) xmemmove(dest,PSTR(src),n)
#define memchr(s,c,n) xmemchr(PSTR(s),c,n)
#define strcat(dst,src) xstrcat(dst,PSTR(src))
#define strncat(dst,src,ssize) xstrncat(dst,PSTR(src),ssize)
#define strcpy(dst,src) xstrcpy(dst,PSTR(src))
#define strncpy(dst,src,dsize) xstrncpy(dst,PSTR(src),dsize)
#define strlen(s) xstrlen(PSTR(s))
#define strcmp(s1,s2) xstrcmp(s1,PSTR(s2))
#define strncmp(s1,s2,n) xstrncmp(s1,PSTR(s2),n)
#else
/* in case wrapped calls are not required */
#define memcmp(s1,s2,n) memcmp_P(s1,PSTR(s2),n)
#define memcpy(dest,src,n) memcpy_P(dest,PSTR(src),n)
#define memmove(dest,src,n) memmove_P(dest,PSTR(src),n)
#define memchr(s,c,n) memchr_P(PSTR(s),c,n)
#define strcat(dst,src) strcat_P(dst,PSTR(src))
#define strncat(dst,src,ssize) strncat_P(dst,PSTR(src),ssize)
#define strcpy(dst,src) strcpy_P(dst,PSTR(src))
#define strncpy(dst,src,dsize) strncpy_P(dst,PSTR(src),dsize)
#define strlen(s) strlen_P(PSTR(s))
#define strcmp(s1,s2) strcmp_P(s1,PSTR(s2))
#define strncmp(s1,s2,n) strncmp_P(s1,PSTR(s2),n)
#endif
static const char Unset[] PROGMEM = "<UNSET>";
const char* it = Unset; /* Routine name for message routines. */
static int errors = 0; static int errors = 0;
/* Complain if condition is not true. */ /* Complain if condition is not true. */
#define check(thing) checkit(thing, __LINE__) #define check(thing) checkit(thing, __LINE__)
static void _DEFUN(checkit, (ok, l), int ok _AND int l) static void checkit(int ok, int l)
{ {
// newfunc(it); // newfunc(it);
// line(l); // line(l);
if (!ok) if (!ok)
{ {
printf("string.c:%d %s\n", l, it); printf(PSTR("string.c:%d %s\n"), l, it);
++errors; ++errors;
} }
} }
/* Complain if first two args don't strcmp as equal. */ /* Complain if first two args don't strcmp as equal. */
#define equal(a, b) funcqual(a, b, __LINE__); #define equal(a, b) funcqual(a, PSTR(b), __LINE__);
static void _DEFUN(funcqual, (a, b, l), char* a _AND char* b _AND int l) static void funcqual(const char *a, const char *b, int l)
{ {
// newfunc(it); // newfunc(it);
// line(l); // line(l);
if (a == NULL && b == NULL) if (a == NULL && b == NULL)
return; return;
if (strcmp(a, b)) if (strcmp_P(a, b))
{ {
printf("string.c:%d (%s)\n", l, it); printf(PSTR("string.c:%d (%s)\n"), l, it);
} }
} }
@ -57,7 +136,7 @@ static char two[50];
void libm_test_string() void libm_test_string()
{ {
/* Test strcmp first because we use it to test other things. */ /* Test strcmp first because we use it to test other things. */
it = "strcmp"; it = PSTR("strcmp");
check(strcmp("", "") == 0); /* Trivial case. */ check(strcmp("", "") == 0); /* Trivial case. */
check(strcmp("a", "a") == 0); /* Identity. */ check(strcmp("a", "a") == 0); /* Identity. */
check(strcmp("abc", "abc") == 0); /* Multicharacter. */ check(strcmp("abc", "abc") == 0); /* Multicharacter. */
@ -69,7 +148,7 @@ void libm_test_string()
check(strcmp("a\103", "a\003") > 0); check(strcmp("a\103", "a\003") > 0);
/* Test strcpy next because we need it to set up other tests. */ /* Test strcpy next because we need it to set up other tests. */
it = "strcpy"; it = PSTR("strcpy");
check(strcpy(one, "abcd") == one); /* Returned value. */ check(strcpy(one, "abcd") == one); /* Returned value. */
equal(one, "abcd"); /* Basic test. */ equal(one, "abcd"); /* Basic test. */
@ -78,7 +157,7 @@ void libm_test_string()
equal(one + 2, "cd"); /* Wrote too much? */ equal(one + 2, "cd"); /* Wrote too much? */
(void)strcpy(two, "hi there"); (void)strcpy(two, "hi there");
(void)strcpy(one, two); (void)xstrcpy(one, two);
equal(one, "hi there"); /* Basic test encore. */ equal(one, "hi there"); /* Basic test encore. */
equal(two, "hi there"); /* Stomped on source? */ equal(two, "hi there"); /* Stomped on source? */
@ -86,7 +165,7 @@ void libm_test_string()
equal(one, ""); /* Boundary condition. */ equal(one, ""); /* Boundary condition. */
/* strcat. */ /* strcat. */
it = "strcat"; it = PSTR("strcat");
(void)strcpy(one, "ijk"); (void)strcpy(one, "ijk");
check(strcat(one, "lmn") == one); /* Returned value. */ check(strcat(one, "lmn") == one); /* Returned value. */
equal(one, "ijklmn"); /* Basic test. */ equal(one, "ijklmn"); /* Basic test. */
@ -98,7 +177,7 @@ void libm_test_string()
(void)strcpy(one, "gh"); (void)strcpy(one, "gh");
(void)strcpy(two, "ef"); (void)strcpy(two, "ef");
(void)strcat(one, two); (void)xstrcpy(one, two);
equal(one, "ghef"); /* Basic test encore. */ equal(one, "ghef"); /* Basic test encore. */
equal(two, "ef"); /* Stomped on source? */ equal(two, "ef"); /* Stomped on source? */
@ -114,42 +193,67 @@ void libm_test_string()
/* strncat - first test it as strcat, with big counts, /* strncat - first test it as strcat, with big counts,
then test the count mechanism. */ then test the count mechanism. */
it = "strncat"; it = PSTR("strncat");
(void)strcpy(one, "ijk"); (void)strcpy(one, "ijk");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
check(strncat(one, "lmn", 99) == one); /* Returned value. */ check(strncat(one, "lmn", 99) == one); /* Returned value. */
#pragma GCC diagnostic pop
equal(one, "ijklmn"); /* Basic test. */ equal(one, "ijklmn"); /* Basic test. */
(void)strcpy(one, "x"); (void)strcpy(one, "x");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
(void)strncat(one, "yz", 99); (void)strncat(one, "yz", 99);
#pragma GCC diagnostic pop
equal(one, "xyz"); /* Writeover. */ equal(one, "xyz"); /* Writeover. */
equal(one + 4, "mn"); /* Wrote too much? */ equal(one + 4, "mn"); /* Wrote too much? */
(void)strcpy(one, "gh"); (void)strcpy(one, "gh");
(void)strcpy(two, "ef"); (void)strcpy(two, "ef");
(void)strncat(one, two, 99); #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds="
#pragma GCC diagnostic ignored "-Wstringop-overflow="
(void)xstrncat(one, two, 99);
#pragma GCC diagnostic pop
equal(one, "ghef"); /* Basic test encore. */ equal(one, "ghef"); /* Basic test encore. */
equal(two, "ef"); /* Stomped on source? */ equal(two, "ef"); /* Stomped on source? */
(void)strcpy(one, ""); (void)strcpy(one, "");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
(void)strncat(one, "", 99); (void)strncat(one, "", 99);
#pragma GCC diagnostic pop
equal(one, ""); /* Boundary conditions. */ equal(one, ""); /* Boundary conditions. */
(void)strcpy(one, "ab"); (void)strcpy(one, "ab");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
(void)strncat(one, "", 99); (void)strncat(one, "", 99);
#pragma GCC diagnostic pop
equal(one, "ab"); equal(one, "ab");
(void)strcpy(one, ""); (void)strcpy(one, "");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
(void)strncat(one, "cd", 99); (void)strncat(one, "cd", 99);
#pragma GCC diagnostic pop
equal(one, "cd"); equal(one, "cd");
(void)strcpy(one, "ab"); (void)strcpy(one, "ab");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
(void)strncat(one, "cdef", 2); (void)strncat(one, "cdef", 2);
#pragma GCC diagnostic pop
equal(one, "abcd"); /* Count-limited. */ equal(one, "abcd"); /* Count-limited. */
(void)strncat(one, "gh", 0); (void)strncat(one, "gh", 0);
equal(one, "abcd"); /* Zero count. */ equal(one, "abcd"); /* Zero count. */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
(void)strncat(one, "gh", 2); (void)strncat(one, "gh", 2);
#pragma GCC diagnostic pop
equal(one, "abcdgh"); /* Count _AND length equal. */ equal(one, "abcdgh"); /* Count _AND length equal. */
it = "strncmp"; it = PSTR("strncmp");
/* strncmp - first test as strcmp with big counts";*/ /* strncmp - first test as strcmp with big counts";*/
check(strncmp("", "", 99) == 0); /* Trivial case. */ check(strncmp("", "", 99) == 0); /* Trivial case. */
check(strncmp("a", "a", 99) == 0); /* Identity. */ check(strncmp("a", "a", 99) == 0); /* Identity. */
@ -164,16 +268,22 @@ void libm_test_string()
check(strncmp("abc", "def", 0) == 0); /* Zero count. */ check(strncmp("abc", "def", 0) == 0); /* Zero count. */
/* strncpy - testing is a bit different because of odd semantics. */ /* strncpy - testing is a bit different because of odd semantics. */
it = "strncpy"; it = PSTR("strncpy");
check(strncpy(one, "abc", 4) == one); /* Returned value. */ check(strncpy(one, "abc", 4) == one); /* Returned value. */
equal(one, "abc"); /* Did the copy go right? */ equal(one, "abc"); /* Did the copy go right? */
(void)strcpy(one, "abcdefgh"); (void)strcpy(one, "abcdefgh");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
(void)strncpy(one, "xyz", 2); (void)strncpy(one, "xyz", 2);
#pragma GCC diagnostic pop
equal(one, "xycdefgh"); /* Copy cut by count. */ equal(one, "xycdefgh"); /* Copy cut by count. */
(void)strcpy(one, "abcdefgh"); (void)strcpy(one, "abcdefgh");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
(void)strncpy(one, "xyz", 3); /* Copy cut just before NUL. */ (void)strncpy(one, "xyz", 3); /* Copy cut just before NUL. */
#pragma GCC diagnostic pop
equal(one, "xyzdefgh"); equal(one, "xyzdefgh");
(void)strcpy(one, "abcdefgh"); (void)strcpy(one, "abcdefgh");
@ -188,7 +298,10 @@ void libm_test_string()
equal(one + 5, "fgh"); equal(one + 5, "fgh");
(void)strcpy(one, "abc"); (void)strcpy(one, "abc");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
(void)strncpy(one, "xyz", 0); /* Zero-length copy. */ (void)strncpy(one, "xyz", 0); /* Zero-length copy. */
#pragma GCC diagnostic pop
equal(one, "abc"); equal(one, "abc");
(void)strncpy(one, "", 2); /* Zero-length source. */ (void)strncpy(one, "", 2); /* Zero-length source. */
@ -197,18 +310,18 @@ void libm_test_string()
equal(one + 2, "c"); equal(one + 2, "c");
(void)strcpy(one, "hi there"); (void)strcpy(one, "hi there");
(void)strncpy(two, one, 9); (void)xstrncpy(two, one, 9);
equal(two, "hi there"); /* Just paranoia. */ equal(two, "hi there"); /* Just paranoia. */
equal(one, "hi there"); /* Stomped on source? */ equal(one, "hi there"); /* Stomped on source? */
/* strlen. */ /* strlen. */
it = "strlen"; it = PSTR("strlen");
check(strlen("") == 0); /* Empty. */ check(strlen("") == 0); /* Empty. */
check(strlen("a") == 1); /* Single char. */ check(strlen("a") == 1); /* Single char. */
check(strlen("abcd") == 4); /* Multiple chars. */ check(strlen("abcd") == 4); /* Multiple chars. */
/* strchr. */ /* strchr. */
it = "strchr"; it = PSTR("strchr");
check(strchr("abcd", 'z') == NULL); /* Not found. */ check(strchr("abcd", 'z') == NULL); /* Not found. */
(void)strcpy(one, "abcd"); (void)strcpy(one, "abcd");
check(strchr(one, 'c') == one + 2); /* Basic test. */ check(strchr(one, 'c') == one + 2); /* Basic test. */
@ -222,7 +335,7 @@ void libm_test_string()
check(strchr(one, '\0') == one); /* NUL in empty string. */ check(strchr(one, '\0') == one); /* NUL in empty string. */
/* index - just like strchr. */ /* index - just like strchr. */
it = "index"; it = PSTR("index");
check(index("abcd", 'z') == NULL); /* Not found. */ check(index("abcd", 'z') == NULL); /* Not found. */
(void)strcpy(one, "abcd"); (void)strcpy(one, "abcd");
check(index(one, 'c') == one + 2); /* Basic test. */ check(index(one, 'c') == one + 2); /* Basic test. */
@ -236,7 +349,7 @@ void libm_test_string()
check(index(one, '\0') == one); /* NUL in empty string. */ check(index(one, '\0') == one); /* NUL in empty string. */
/* strrchr. */ /* strrchr. */
it = "strrchr"; it = PSTR("strrchr");
check(strrchr("abcd", 'z') == NULL); /* Not found. */ check(strrchr("abcd", 'z') == NULL); /* Not found. */
(void)strcpy(one, "abcd"); (void)strcpy(one, "abcd");
check(strrchr(one, 'c') == one + 2); /* Basic test. */ check(strrchr(one, 'c') == one + 2); /* Basic test. */
@ -250,7 +363,7 @@ void libm_test_string()
check(strrchr(one, '\0') == one); /* NUL in empty string. */ check(strrchr(one, '\0') == one); /* NUL in empty string. */
/* rindex - just like strrchr. */ /* rindex - just like strrchr. */
it = "rindex"; it = PSTR("rindex");
check(rindex("abcd", 'z') == NULL); /* Not found. */ check(rindex("abcd", 'z') == NULL); /* Not found. */
(void)strcpy(one, "abcd"); (void)strcpy(one, "abcd");
check(rindex(one, 'c') == one + 2); /* Basic test. */ check(rindex(one, 'c') == one + 2); /* Basic test. */
@ -264,7 +377,7 @@ void libm_test_string()
check(rindex(one, '\0') == one); /* NUL in empty string. */ check(rindex(one, '\0') == one); /* NUL in empty string. */
/* strpbrk - somewhat like strchr. */ /* strpbrk - somewhat like strchr. */
it = "strpbrk"; it = PSTR("strpbrk");
check(strpbrk("abcd", "z") == NULL); /* Not found. */ check(strpbrk("abcd", "z") == NULL); /* Not found. */
(void)strcpy(one, "abcd"); (void)strcpy(one, "abcd");
check(strpbrk(one, "c") == one + 2); /* Basic test. */ check(strpbrk(one, "c") == one + 2); /* Basic test. */
@ -281,7 +394,7 @@ void libm_test_string()
check(strpbrk(one, "") == NULL); /* Both strings empty. */ check(strpbrk(one, "") == NULL); /* Both strings empty. */
/* strstr - somewhat like strchr. */ /* strstr - somewhat like strchr. */
it = "strstr"; it = PSTR("strstr");
check(strstr("z", "abcd") == NULL); /* Not found. */ check(strstr("z", "abcd") == NULL); /* Not found. */
check(strstr("abx", "abcd") == NULL); /* Dead end. */ check(strstr("abx", "abcd") == NULL); /* Dead end. */
(void)strcpy(one, "abcd"); (void)strcpy(one, "abcd");
@ -304,7 +417,7 @@ void libm_test_string()
check(strstr(one, "bbca") == one + 1); /* With overlap. */ check(strstr(one, "bbca") == one + 1); /* With overlap. */
/* strspn. */ /* strspn. */
it = "strspn"; it = PSTR("strspn");
check(strspn("abcba", "abc") == 5); /* Whole string. */ check(strspn("abcba", "abc") == 5); /* Whole string. */
check(strspn("abcba", "ab") == 2); /* Partial. */ check(strspn("abcba", "ab") == 2); /* Partial. */
check(strspn("abc", "qx") == 0); /* None. */ check(strspn("abc", "qx") == 0); /* None. */
@ -312,7 +425,7 @@ void libm_test_string()
check(strspn("abc", "") == 0); /* Null search list. */ check(strspn("abc", "") == 0); /* Null search list. */
/* strcspn. */ /* strcspn. */
it = "strcspn"; it = PSTR("strcspn");
check(strcspn("abcba", "qx") == 5); /* Whole string. */ check(strcspn("abcba", "qx") == 5); /* Whole string. */
check(strcspn("abcba", "cx") == 2); /* Partial. */ check(strcspn("abcba", "cx") == 2); /* Partial. */
check(strcspn("abc", "abc") == 0); /* None. */ check(strcspn("abc", "abc") == 0); /* None. */
@ -320,7 +433,7 @@ void libm_test_string()
check(strcspn("abc", "") == 3); /* Null search list. */ check(strcspn("abc", "") == 3); /* Null search list. */
/* strtok - the hard one. */ /* strtok - the hard one. */
it = "strtok"; it = PSTR("strtok");
(void)strcpy(one, "first, second, third"); (void)strcpy(one, "first, second, third");
equal(strtok(one, ", "), "first"); /* Basic test. */ equal(strtok(one, ", "), "first"); /* Basic test. */
equal(one, "first"); equal(one, "first");
@ -367,7 +480,7 @@ void libm_test_string()
equal(one + 4, "c"); equal(one + 4, "c");
/* memcmp. */ /* memcmp. */
it = "memcmp"; it = PSTR("memcmp");
check(memcmp("a", "a", 1) == 0); /* Identity. */ check(memcmp("a", "a", 1) == 0); /* Identity. */
check(memcmp("abc", "abc", 3) == 0); /* Multicharacter. */ check(memcmp("abc", "abc", 3) == 0); /* Multicharacter. */
check(memcmp("abcd", "abce", 4) < 0); /* Honestly unequal. */ check(memcmp("abcd", "abce", 4) < 0); /* Honestly unequal. */
@ -379,25 +492,25 @@ void libm_test_string()
/* memcmp should test strings as unsigned */ /* memcmp should test strings as unsigned */
one[0] = 0xfe; one[0] = 0xfe;
two[0] = 0x03; two[0] = 0x03;
check(memcmp(one, two, 1) > 0); check(xmemcmp(one, two, 1) > 0);
/* memchr. */ /* memchr. */
it = "memchr"; it = PSTR("memchr");
check(memchr("abcd", 'z', 4) == NULL); /* Not found. */ check(memchr("abcd", 'z', 4) == NULL); /* Not found. */
(void)strcpy(one, "abcd"); (void)strcpy(one, "abcd");
check(memchr(one, 'c', 4) == one + 2); /* Basic test. */ check(xmemchr(one, 'c', 4) == one + 2); /* Basic test. */
check(memchr(one, 'd', 4) == one + 3); /* End of string. */ check(xmemchr(one, 'd', 4) == one + 3); /* End of string. */
check(memchr(one, 'a', 4) == one); /* Beginning. */ check(xmemchr(one, 'a', 4) == one); /* Beginning. */
check(memchr(one, '\0', 5) == one + 4); /* Finding NUL. */ check(xmemchr(one, '\0', 5) == one + 4); /* Finding NUL. */
(void)strcpy(one, "ababa"); (void)strcpy(one, "ababa");
check(memchr(one, 'b', 5) == one + 1); /* Finding first. */ check(xmemchr(one, 'b', 5) == one + 1); /* Finding first. */
check(memchr(one, 'b', 0) == NULL); /* Zero count. */ check(xmemchr(one, 'b', 0) == NULL); /* Zero count. */
check(memchr(one, 'a', 1) == one); /* Singleton case. */ check(xmemchr(one, 'a', 1) == one); /* Singleton case. */
(void)strcpy(one, "a\203b"); (void)strcpy(one, "a\203b");
check(memchr(one, 0203, 3) == one + 1); /* Unsignedness. */ check(xmemchr(one, 0203, 3) == one + 1); /* Unsignedness. */
/* memcpy - need not work for overlap. */ /* memcpy - need not work for overlap. */
it = "memcpy"; it = PSTR("memcpy");
check(memcpy(one, "abc", 4) == one); /* Returned value. */ check(memcpy(one, "abc", 4) == one); /* Returned value. */
equal(one, "abc"); /* Did the copy go right? */ equal(one, "abc"); /* Did the copy go right? */
@ -411,13 +524,13 @@ void libm_test_string()
(void)strcpy(one, "hi there"); (void)strcpy(one, "hi there");
(void)strcpy(two, "foo"); (void)strcpy(two, "foo");
(void)memcpy(two, one, 9); (void)xmemcpy(two, one, 9);
equal(two, "hi there"); /* Just paranoia. */ equal(two, "hi there"); /* Just paranoia. */
equal(one, "hi there"); /* Stomped on source? */ equal(one, "hi there"); /* Stomped on source? */
#if 0 #if 1
/* memmove - must work on overlap. */ /* memmove - must work on overlap. */
it = "memmove"; it = PSTR("memmove");
check(memmove(one, "abc", 4) == one); /* Returned value. */ check(xmemmove(one, "abc", 4) == one); /* Returned value. */
equal(one, "abc"); /* Did the copy go right? */ equal(one, "abc"); /* Did the copy go right? */
(void) strcpy(one, "abcdefgh"); (void) strcpy(one, "abcdefgh");
@ -430,20 +543,20 @@ void libm_test_string()
(void) strcpy(one, "hi there"); (void) strcpy(one, "hi there");
(void) strcpy(two, "foo"); (void) strcpy(two, "foo");
(void) memmove(two, one, 9); (void) xmemmove(two, one, 9);
equal(two, "hi there"); /* Just paranoia. */ equal(two, "hi there"); /* Just paranoia. */
equal(one, "hi there"); /* Stomped on source? */ equal(one, "hi there"); /* Stomped on source? */
(void) strcpy(one, "abcdefgh"); (void) strcpy(one, "abcdefgh");
(void) memmove(one+1, one, 9); (void) xmemmove(one+1, one, 9);
equal(one, "aabcdefgh"); /* Overlap, right-to-left. */ equal(one, "aabcdefgh"); /* Overlap, right-to-left. */
(void) strcpy(one, "abcdefgh"); (void) strcpy(one, "abcdefgh");
(void) memmove(one+1, one+2, 7); (void) xmemmove(one+1, one+2, 7);
equal(one, "acdefgh"); /* Overlap, left-to-right. */ equal(one, "acdefgh"); /* Overlap, left-to-right. */
(void) strcpy(one, "abcdefgh"); (void) strcpy(one, "abcdefgh");
(void) memmove(one, one, 9); (void) xmemmove(one, one, 9);
equal(one, "abcdefgh"); /* 100% overlap. */ equal(one, "abcdefgh"); /* 100% overlap. */
#endif #endif
#if 0 #if 0
@ -451,7 +564,7 @@ void libm_test_string()
The SVID, the only place where memccpy is mentioned, says The SVID, the only place where memccpy is mentioned, says
overlap might fail, so we don't try it. Besides, it's hard overlap might fail, so we don't try it. Besides, it's hard
to see the rationale for a non-left-to-right memccpy. */ to see the rationale for a non-left-to-right memccpy. */
it = "memccpy"; it = PSTR("memccpy");
check(memccpy(one, "abc", 'q', 4) == NULL); /* Returned value. */ check(memccpy(one, "abc", 'q', 4) == NULL); /* Returned value. */
equal(one, "abc"); /* Did the copy go right? */ equal(one, "abc"); /* Did the copy go right? */
@ -486,12 +599,15 @@ void libm_test_string()
equal(two, "xbcdlebee"); equal(two, "xbcdlebee");
#endif #endif
/* memset. */ /* memset. */
it = "memset"; it = PSTR("memset");
(void)strcpy(one, "abcdefgh"); (void)strcpy(one, "abcdefgh");
check(memset(one + 1, 'x', 3) == one + 1); /* Return value. */ check(memset(one + 1, 'x', 3) == one + 1); /* Return value. */
equal(one, "axxxefgh"); /* Basic test. */ equal(one, "axxxefgh"); /* Basic test. */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmemset-transposed-args"
(void)memset(one + 2, 'y', 0); (void)memset(one + 2, 'y', 0);
#pragma GCC diagnostic pop
equal(one, "axxxefgh"); /* Zero-length set. */ equal(one, "axxxefgh"); /* Zero-length set. */
(void)memset(one + 5, 0, 1); (void)memset(one + 5, 0, 1);
@ -503,7 +619,7 @@ void libm_test_string()
/* bcopy - much like memcpy. /* bcopy - much like memcpy.
Berklix manual is silent about overlap, so don't test it. */ Berklix manual is silent about overlap, so don't test it. */
it = "bcopy"; it = PSTR("bcopy");
(void)bcopy("abc", one, 4); (void)bcopy("abc", one, 4);
equal(one, "abc"); /* Simple copy. */ equal(one, "abc"); /* Simple copy. */
@ -522,7 +638,7 @@ void libm_test_string()
equal(one, "hi there"); /* Stomped on source? */ equal(one, "hi there"); /* Stomped on source? */
/* bzero. */ /* bzero. */
it = "bzero"; it = PSTR("bzero");
(void)strcpy(one, "abcdef"); (void)strcpy(one, "abcdef");
bzero(one + 2, 2); bzero(one + 2, 2);
equal(one, "ab"); /* Basic test. */ equal(one, "ab"); /* Basic test. */
@ -534,7 +650,7 @@ void libm_test_string()
equal(one, "abcdef"); /* Zero-length copy. */ equal(one, "abcdef"); /* Zero-length copy. */
/* bcmp - somewhat like memcmp. */ /* bcmp - somewhat like memcmp. */
it = "bcmp"; it = PSTR("bcmp");
check(bcmp("a", "a", 1) == 0); /* Identity. */ check(bcmp("a", "a", 1) == 0); /* Identity. */
check(bcmp("abc", "abc", 3) == 0); /* Multicharacter. */ check(bcmp("abc", "abc", 3) == 0); /* Multicharacter. */
check(bcmp("abcd", "abce", 4) != 0); /* Honestly unequal. */ check(bcmp("abcd", "abce", 4) != 0); /* Honestly unequal. */

View File

@ -62,6 +62,7 @@ int errors = 0;
printf printf
/* A safe target-independent memmove. */ /* A safe target-independent memmove. */
void mymemmove(unsigned char* dest, unsigned char* src, size_t n) __attribute__((__noinline__));
void mymemmove(unsigned char* dest, unsigned char* src, size_t n) void mymemmove(unsigned char* dest, unsigned char* src, size_t n)
{ {

View File

@ -31,18 +31,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#define memcmp memcmp_P
#define memcpy memcpy_P #define memcpy memcpy_P
#define memmem memmem_P
#define memchr memchr_P
#define strcat strcat_P
#define strncat strncat_P
#define strcpy strcpy_P
#define strncpy strncpy_P
#define strlen strlen_P
#define strnlen strnlen_P
#define strcmp strcmp_P #define strcmp strcmp_P
#define strncmp strncmp_P
#define BUFF_SIZE 256 #define BUFF_SIZE 256

View File

@ -0,0 +1,4 @@
/*@create-file:build.opt@
-fno-builtin
*/

View File

@ -13,6 +13,7 @@
#define MAX_1 50 #define MAX_1 50
#define memcmp memcmp_P #define memcmp memcmp_P
#define memcpy memcpy_P #define memcpy memcpy_P
#define memmove memmove_P
#define memmem memmem_P #define memmem memmem_P
#define memchr memchr_P #define memchr memchr_P
#define strcat strcat_P #define strcat strcat_P
@ -86,6 +87,8 @@ void tstring_main(void)
tmp2[0] = 'Z'; tmp2[0] = 'Z';
tmp2[1] = '\0'; tmp2[1] = '\0';
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmemset-transposed-args"
if (memset(target, 'X', 0) != target || memcpy(target, "Y", 0) != target if (memset(target, 'X', 0) != target || memcpy(target, "Y", 0) != target
|| memmove(target, "K", 0) != target || strncpy(tmp2, "4", 0) != tmp2 || memmove(target, "K", 0) != target || strncpy(tmp2, "4", 0) != tmp2
|| strncat(tmp2, "123", 0) != tmp2 || strcat(target, "") != target) || strncat(tmp2, "123", 0) != tmp2 || strcat(target, "") != target)
@ -93,6 +96,7 @@ void tstring_main(void)
eprintf(__LINE__, target, "A", 0); eprintf(__LINE__, target, "A", 0);
test_failed = 1; test_failed = 1;
} }
#pragma GCC diagnostic pop
if (strcmp(target, "A") || strlen(target) != 1 || memchr(target, 'A', 0) != NULL if (strcmp(target, "A") || strlen(target) != 1 || memchr(target, 'A', 0) != NULL
|| memcmp(target, "J", 0) || strncmp(target, "A", 1) || strncmp(target, "J", 0) || memcmp(target, "J", 0) || strncmp(target, "A", 1) || strncmp(target, "J", 0)

View File

@ -1,5 +1,5 @@
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include "FS.h" #include <LittleFS.h>
#include <BSTest.h> #include <BSTest.h>
BS_ENV_DECLARE(); BS_ENV_DECLARE();
@ -18,17 +18,17 @@ bool pretest()
TEST_CASE("read-write test","[fs]") TEST_CASE("read-write test","[fs]")
{ {
REQUIRE(SPIFFS.begin()); REQUIRE(LittleFS.begin());
String text = "write test"; String text = "write test";
{ {
File out = SPIFFS.open("/tmp.txt", "w"); File out = LittleFS.open("/tmp.txt", "w");
REQUIRE(out); REQUIRE(out);
out.print(text); out.print(text);
} }
{ {
File in = SPIFFS.open("/tmp.txt", "r"); File in = LittleFS.open("/tmp.txt", "r");
REQUIRE(in); REQUIRE(in);
CHECK(in.size() == text.length()); CHECK(in.size() == text.length());
in.setTimeout(0); in.setTimeout(0);
@ -39,14 +39,14 @@ TEST_CASE("read-write test","[fs]")
TEST_CASE("A bunch of files show up in openDir, and can be removed", "[fs]") TEST_CASE("A bunch of files show up in openDir, and can be removed", "[fs]")
{ {
REQUIRE(SPIFFS.begin()); REQUIRE(LittleFS.begin());
const int n = 10; const int n = 10;
int found[n] = {0}; int found[n] = {0};
{ {
Dir root = SPIFFS.openDir(""); Dir root = LittleFS.openDir("");
while (root.next()) { while (root.next()) {
CHECK(SPIFFS.remove(root.fileName())); CHECK(LittleFS.remove(root.fileName()));
} }
} }
@ -55,14 +55,14 @@ TEST_CASE("A bunch of files show up in openDir, and can be removed", "[fs]")
name += i; name += i;
name += ".txt"; name += ".txt";
File out = SPIFFS.open(name, "w"); File out = LittleFS.open(name, "w");
REQUIRE(out); REQUIRE(out);
out.println(i); out.println(i);
} }
{ {
Dir root = SPIFFS.openDir("/"); Dir root = LittleFS.openDir("/");
while (root.next()) { while (root.next()) {
String fileName = root.fileName(); String fileName = root.fileName();
CHECK(fileName.indexOf("/seq_") == 0); CHECK(fileName.indexOf("/seq_") == 0);
@ -77,35 +77,35 @@ TEST_CASE("A bunch of files show up in openDir, and can be removed", "[fs]")
} }
{ {
Dir root = SPIFFS.openDir("/"); Dir root = LittleFS.openDir("/");
while (root.next()) { while (root.next()) {
String fileName = root.fileName(); String fileName = root.fileName();
CHECK(SPIFFS.remove(fileName)); CHECK(LittleFS.remove(fileName));
} }
} }
} }
TEST_CASE("files can be renamed", "[fs]") TEST_CASE("files can be renamed", "[fs]")
{ {
REQUIRE(SPIFFS.begin()); REQUIRE(LittleFS.begin());
{ {
File tmp = SPIFFS.open("/tmp1.txt", "w"); File tmp = LittleFS.open("/tmp1.txt", "w");
tmp.println("rename test"); tmp.println("rename test");
} }
{ {
CHECK(SPIFFS.rename("/tmp1.txt", "/tmp2.txt")); CHECK(LittleFS.rename("/tmp1.txt", "/tmp2.txt"));
File tmp2 = SPIFFS.open("/tmp2.txt", "r"); File tmp2 = LittleFS.open("/tmp2.txt", "r");
CHECK(tmp2); CHECK(tmp2);
} }
} }
TEST_CASE("FS::info works","[fs]") TEST_CASE("FS::info works","[fs]")
{ {
REQUIRE(SPIFFS.begin()); REQUIRE(LittleFS.begin());
FSInfo info; FSInfo info;
CHECK(SPIFFS.info(info)); CHECK(LittleFS.info(info));
Serial.printf("Total: %u\nUsed: %u\nBlock: %u\nPage: %u\nMax open files: %u\nMax path len: %u\n", Serial.printf("Total: %u\nUsed: %u\nBlock: %u\nPage: %u\nMax open files: %u\nMax path len: %u\n",
info.totalBytes, info.totalBytes,
@ -119,10 +119,10 @@ TEST_CASE("FS::info works","[fs]")
TEST_CASE("FS is empty after format","[fs]") TEST_CASE("FS is empty after format","[fs]")
{ {
REQUIRE(SPIFFS.begin()); REQUIRE(LittleFS.begin());
REQUIRE(SPIFFS.format()); REQUIRE(LittleFS.format());
Dir root = SPIFFS.openDir("/"); Dir root = LittleFS.openDir("/");
int count = 0; int count = 0;
while (root.next()) { while (root.next()) {
++count; ++count;
@ -132,12 +132,12 @@ TEST_CASE("FS is empty after format","[fs]")
TEST_CASE("Can reopen empty file","[fs]") TEST_CASE("Can reopen empty file","[fs]")
{ {
REQUIRE(SPIFFS.begin()); REQUIRE(LittleFS.begin());
{ {
File tmp = SPIFFS.open("/tmp.txt", "w"); File tmp = LittleFS.open("/tmp.txt", "w");
} }
{ {
File tmp = SPIFFS.open("/tmp.txt", "w"); File tmp = LittleFS.open("/tmp.txt", "w");
CHECK(tmp); CHECK(tmp);
} }
} }

View File

@ -85,6 +85,7 @@ def find_core_files():
) )
if file.is_file() if file.is_file()
and file.suffix in (".c", ".cpp", ".h", ".hpp") and file.suffix in (".c", ".cpp", ".h", ".hpp")
and not GIT_ROOT / "tests/device/test_libc" in file.parents
and not GIT_ROOT / "tests/host/bin" in file.parents and not GIT_ROOT / "tests/host/bin" in file.parents
and not GIT_ROOT / "tests/host/common/catch.hpp" == file and not GIT_ROOT / "tests/host/common/catch.hpp" == file
] ]